#include "InterOpPMIHelper.h"
#include "SPAIopPMIAnnotationViewIter.h" 
#include "SPAIopPMIAnnotationView.h" 
#include "SPAIopPMINoteIter.h"
#include "SPAIopPMIRoughnessIter.h"
#include "SPAIopPMIDatumIter.h"
#include "SPAIopPMIDatumTargetIter.h"
#include "SPAIopPMIGDTIter.h"
#include "SPAIopPMIDimensionIter.h"
#include "SPAIopPMIDimension.h"
#include "SPAIopPMICaptureIter.h"
#include "SPAIopPMICapture.h"
#include "SPAIopPMIAnnotationSet.h"
#include "SPAIopPMIAnnotationSetIter.h"
#include "SPAIopInputPSReference.h"
#include "SPAIopEntityIter.h"
#include "SPAIopPMICapture.h"
#include "SPAIopEntity.h"
#include "SPAIopPMIGDTRefFrame.h"
#include "SPAIopPMIDatumRef.h"
#include "common/logger.h"
#include "SPAIopPMIRoughness.h"
#include "SPAIopPMINote.h"
#include "SPAIopPMINoteTextIter.h"
#include "SPAIopPMIDatumTarget.h"
#include "SPAIopPMIGDTRowIter.h"
#include "SPAIopPMIGDTRow.h"
#include "SPAIopPMIZoneModifierIter.h"
#include "SPAIopPMIZoneModifier.h"
#include "SPAIopPMIDatumRefIter.h"
#include "SPAIopPMIModifiedDatumIter.h"
#include "SPAIopPMIModifiedDatum.h"
#include "SPAIopPMIAnnotationIter.h"
#include "SPAIopPMILeaderIter.h"
#include "SPAIopPMILeader.h"
#include "SPAIopInputPSInstance.h"
#include "SPAIopAcisEntity.h"
#include "SPAIopInstanceEntity.h"
#include "../InterOpUtils.h"
#include <codecvt>
#ifdef _WIN32
#include <concurrencysal.h>
#endif
#include <cstddef>
#include <memory>
#include <spdlog/logger.h>
#include <unordered_map>
#include <vector>
#include "container.hxx"
#include "core/InterOpUtils.h"
#include "entity.hxx"
#include "kernapi.hxx"
#include "lists.hxx"
#include "mmgr.hxx"
#include "pmi/InterOpPMIBase.h"
#include "pmi/InterOpPMINote.h"
#include "pmi/InterOpRoughness.h"
#include "pmi/InterOpPMIDatum.h"
#include "pmi/InterOpGDT.h"
#include "pmi/InterOpDimension.h"

#define INTEROP_READER_PMI_LOG
#ifdef INTEROP_READER_PMI_LOG
#define LOGGER_DEBUG LOG_DEBUG
#else
#define LOGGER_DEBUG(...)
#endif


AMCAX_EXCHANGE_NAMESPACE_BEGIN

namespace InterOp {

	SPAIopWString _inputPSReferenceName;
    void ProcessNote(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMINote& iNote, SPAIopMappingData& iMappingData);
	void ProcessRoughness(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIRoughness& iNote, SPAIopMappingData& iMappingData);
	std::shared_ptr<PMI::PMIInterOpDatum> ProcessDatum(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatum& iDatum, SPAIopMappingData& iMappingData);
	std::shared_ptr<PMI::InterOpPMIDatumTarget> ProcessDatumTarget(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatumTarget& iDatumTarget, SPAIopMappingData& iMappingData);
	void ProcessGDT(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIGDT& iDatumTarget, SPAIopMappingData& iMappingData);
	std::shared_ptr<PMI::GDTRefFrame> ProcessGDTRefFrame(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIGDTRefFrame& iGDTRefFrame);
	std::shared_ptr<PMI::DatumRef> ProcessDatumRef(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatumRef& iDatumRef);
	void ProcessDimension(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDimension& iDimension, SPAIopMappingData& iMappingData);
	void ProcessCapture(SPAIopPMICapture& iCapture, SPAIopMappingData& iMappingData, SPAIopWString iBuffer = SPAIopWString(L""), bool iIsToDumpFull = true);
	void ProcessAnnotationBasicData(SPAIopPMIAnnotation& iAnnotation, SPAIopWString iBuffer = SPAIopWString(L""), bool iIsToDumpFull = true);
	void ProcessAnnotationViewData(SPAIopPMIAnnotationView& iAnnotationView, SPAIopWString iBuffer = SPAIopWString(L""), bool iIsToDumpFull = true);
	void ProcessAnnotationDisplay(SPAIopPMIAnnotation& iAnnotation);
	// void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation, SPAIopMappingData& iMappingData,SPAIopWString iBuffer = SPAIopWString(L""));
	void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation,std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,std::shared_ptr<PMI::InterOpPMIAnnotation> pmiInfo) ;
	// void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation, SPAIopMappingData& iMappingData,const SPAIopWString& iPSReferenceName, const SPAIopWString& iBuffer);
	ENTITY* ProcessEntity(SPAIopEntity& iEntity);
	// ENTITY* ProcessEntity(SPAIopEntity& iEntity, SPAIopMappingData& iMappingData,const SPAIopWString& iPSReferenceName, SPAIopWString iBuffer = SPAIopWString(L""));
	// void ProcessLinkedEntity(const SPAIopEntity& iEntity, SPAIopWString& ioCompPathBuffer, int& ioCompPathCounter,
	// 	SPAIopInputPSInstance& ioPartInstance, SPAIopEntity& ioPartEntity);
	void ProcessLinkedEntity(const SPAIopEntity& iEntity,SPAIopEntity& ioPartEntity);
    void ToString(SPAIopPMIRoughnessObtentionType iObtentionType, SPAIopWString& oObtentionType);
	void ToString(SPAIopPMIRoughnessApplicabilityType iApplicabilityType, SPAIopWString& oApplicabilityType);
	void ToString(SPAIopPMIToleranceType iToleranceType, SPAIopWString& oTolType);
	void ToString(SPAIopPMIToleranceValueType iToleranceValueType, SPAIopWString& oTolValType);
	void ToString(SPAIopPMIToleranceModifier iZoneModifier, SPAIopWString& oZoneModifier);
	void ToString(SPAIopPMIDimensionMainType iDimMainType, SPAIopWString& oDimMainType);
	void ToString(SPAIopPMIDimensionSubType iDimSubType, SPAIopWString& oDimSubType);
	void ToString(SPAIopPMICalloutFeatureAnnotationType iCalloutFeatureAnnotType, SPAIopWString& oCalloutFeatureAnnotType);
	void ToString(SPAIopPMIUnit iUnit, SPAIopWString& oUnit);
	void ToString(SPAIopPMIArrowSymbol iArrowSymbol, SPAIopWString& oArrowSymbol);
	void ToString(SPAIopPMICameraType iCameraType, SPAIopWString& oCameraType);
	void ToString(SPAIopPMIAnnotationType iAnnotType, SPAIopWString& oAnnotType);
	void ToString(SPAIopPMIOrientation iOrientation, SPAIopWString& oOrientation);

	std::string wstring_to_utf8(const std::wstring& wstr) {
		std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
		return converter.to_bytes(wstr);
	}

	std::string wstring_to_utf8(const wchar_t wstr) {
		std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
		return converter.to_bytes(wstr);
	}

    void TraverserPMIData(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,const SPAIopPMIData &pmiData,SPAIopMappingData & mappingData, bool iIsAssemblyPMI) 
    {
        SPAIopPMIAnnotationSetIter setIter = pmiData.GetSetIterator();
        int iSet = 0;
        while (setIter.Next())
        {
            SPAIopPMIAnnotationSet annSet = setIter.Current();
            SPAIopInputPSReference inputPSReference = annSet.GetReference();
            _inputPSReferenceName = inputPSReference.GetReferenceName();
            if (iIsAssemblyPMI) {
                SPAIopWString storageName = inputPSReference.GetStorageName();
                SPAIopWString fileName;   
                // TODO: 装配体如何处理PMI信息
            }
            SPAIopPMIAnnotationViewIter viewIter = annSet.GetViewIterator();
            int iView = 0;
            while (viewIter.Next())
            {
    
                SPAIopPMIAnnotationView annView = viewIter.Current();
    
                // Iterate on specific types only...
                SPAIopPMINoteIter noteIter = annView.GetNoteIterator();
                while (noteIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing Note PMI ===================== \n\n");
    
                    SPAIopPMINote& note = noteIter.Current();
                    ProcessNote(oPMIInfos,note, mappingData);
                }
    
                SPAIopPMIRoughnessIter roughIter = annView.GetRoughnessIterator();
                while (roughIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing Roughness PMI ===================== \n\n");
    
                    SPAIopPMIRoughness& roughness = roughIter.Current();
                    ProcessRoughness(oPMIInfos,roughness, mappingData);
                }
    
                SPAIopPMIDatumIter datumIter = annView.GetDatumIterator();
                while (datumIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing Datum PMI ===================== \n\n");
    
                    SPAIopPMIDatum& datum = datumIter.Current();
                    ProcessDatum(oPMIInfos,datum, mappingData);
                }
    
                SPAIopPMIDatumTargetIter datumTargetIter = annView.GetDatumTargetIterator();
                while (datumTargetIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing Datum Target PMI ===================== \n\n");
    
                    SPAIopPMIDatumTarget& datumTarget = datumTargetIter.Current();
                    ProcessDatumTarget(oPMIInfos,datumTarget, mappingData);
                }
    
                SPAIopPMIGDTIter gdtIter = annView.GetGDTIterator();
                while (gdtIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing GDT PMI ===================== \n\n");
    
                    SPAIopPMIGDT& gdt = gdtIter.Current();
                    ProcessGDT(oPMIInfos,gdt, mappingData);
                }
    
                SPAIopPMIDimensionIter dimensionIter = annView.GetDimensionIterator();
                while (dimensionIter.Next())
                {
                    LOGGER_DEBUG("\n ===================== Processing Dimension PMI ===================== \n\n");
    
                    SPAIopPMIDimension& dimension = dimensionIter.Current();
                    ProcessDimension(oPMIInfos,dimension, mappingData);
    
                    SPAIopPMIDimensionIter calloutDimensionIter = dimension.GetDimensionIterator();
                    while (calloutDimensionIter.Next())
                    {
                        LOGGER_DEBUG("\n ===================== Processing Hole Callout Dimension PMI ===================== \n\n");
    
                        SPAIopPMIDimension& calloutDimension = calloutDimensionIter.Current();
                        ProcessDimension(oPMIInfos,calloutDimension, mappingData);
                    }
                }
    
                LOGGER_DEBUG("\n =========== End of Processing Annotation View Index = {} =========== \n", iView);
    
                iView++;
            }
    
            // Traversal of the captures in the current set
            SPAIopPMICaptureIter captureIter = annSet.GetCaptureIterator();
            int iCapture = 0;
            while (captureIter.Next())
            {
                LOGGER_DEBUG("\n ===================== Processing Capture ===================== \n\n");
    
                SPAIopPMICapture capture = captureIter.Current();
                ProcessCapture(capture, mappingData);
                iCapture++;
            }
    
            // Traversal of the Constructed Geometries in the current set
            SPAIopEntityIter constGeomIter = annSet.GetConstructedGeometryIterator();
            int iConstGeom = 0;
            while (constGeomIter.Next())
            {
                LOGGER_DEBUG("\n ===================== Processing Constructed Geometry ===================== \n\n");
    
                iConstGeom++;
                SPAIopEntity constGeomEntity = constGeomIter.Current();
                LOGGER_DEBUG(" Constructed Geometry:\n");
                // ProcessEntity(constGeomEntity, mappingData, _inputPSReferenceName, SPAIopWString(L"\t"));
				ProcessEntity(constGeomEntity);
            }
    
        }
    }

    void ProcessNote(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMINote& iNote, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::InterOpNote> exchangePmiNote = std::make_shared<PMI::InterOpNote>() ;
		exchangePmiNote->SetId(SPAIopWStringToString(iNote.GetID())) ;
		exchangePmiNote->SetName(SPAIopWStringToString(iNote.GetName())) ;
		exchangePmiNote->SetIsHide(iNote.IsHidden()) ;
		exchangePmiNote->SetIsFlagNote(iNote.IsFlagNote())  ;
		exchangePmiNote->SetIsNOA(iNote.IsNOA()) ;
		SPAIopPMINoteTextIter textIter = iNote.GetTextIterator();
		while (textIter.Next())
		{
			SPAIopPMINote::Text text = textIter.Current();
			PMI::InterOpNote::Text exchangeText ;
			exchangeText.label = SPAIopWStringToString(text.Label) ;
			exchangeText.fontName = SPAIopWStringToString(text.FontName) ;
			exchangeText.fontType = PMI::Helper::ToFont(text.FontType) ;
			exchangeText.fixedPitch = text.FixedPitch ;
			exchangeText.height = text.Height ;
			exchangeText.bold = text.Bold ;
			exchangeText.italic = text.Italic ;
			exchangeText.underline = text.Underline ;
			exchangeText.strikeThrough = text.StrikeThrough ;
			exchangeText.overline = text.Overline ;
			exchangeText.ratio = text.Ratio ;
			exchangeText.slant = text.Slant ;
			exchangeText.rgbaColor[0] = text.RGBAColor[0] ;
			exchangeText.rgbaColor[1] = text.RGBAColor[1] ;
			exchangeText.rgbaColor[2] = text.RGBAColor[2] ;
			exchangeText.rgbaColor[3] = text.RGBAColor[3] ;
			exchangePmiNote->AddText(exchangeText) ;
		}
#if 0
        ProcessAnnotationBasicData(iNote);   
        bool isFlagNote = iNote.IsFlagNote();
		bool isNOA = iNote.IsNOA();

		SPAIopWString noteType;
		if (true == isFlagNote)
			noteType = (SPAIopWString)L"Flag Note";
		else if (true == isNOA)
			noteType = (SPAIopWString)L"NOA";
		else
			noteType = (SPAIopWString)L"Note";

		//LOGGER_DEBUG(" NoteType = %ls \n", ( const wchar_t*)noteType);
		const wchar_t *pNoteTypeArray = NULL;
		noteType.ToWChar(pNoteTypeArray);
		
	    LOGGER_DEBUG(" NoteType = {} \n", wstring_to_utf8(pNoteTypeArray));
		// spdlog::logger.info(" NoteType = {}", pNoteTypeArray);
		SPAIopPMINoteTextIter textIter = iNote.GetTextIterator();
		int nText = 0;
		while (textIter.Next())
		{
			SPAIopPMINote::Text text = textIter.Current();
			//LOGGER_DEBUG(" Text #:%d  Label = %ls, FontName = %ls \n", nText, ( const wchar_t*)text.Label, ( const wchar_t*)text.FontName);
			SPAIopWString textLabel = text.Label;
			const wchar_t* ptextLabel = NULL;
			textLabel.ToWChar(ptextLabel);
			SPAIopWString testFontName = text.FontName;
			const wchar_t* pTestFontNameArray = NULL;
			testFontName.ToWChar(pTestFontNameArray);
			LOGGER_DEBUG(" Text #: {}  Label = {}, FontName = {} \n", nText, wstring_to_utf8(ptextLabel), wstring_to_utf8(pTestFontNameArray));
			nText++;
		}
#endif
		ProcessAnnotationDisplay(iNote);
		// ProcessLinkedEntities(iNote, iMappingData);
		
		ProcessLinkedEntities(iNote,oPMIInfos,exchangePmiNote) ;
    }

	void ProcessRoughness(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIRoughness& iRoughness, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::InterOpRoughness> exchangePmiRoughness = std::make_shared<PMI::InterOpRoughness>() ;
		exchangePmiRoughness->SetId(SPAIopWStringToString(iRoughness.GetID())) ;
		exchangePmiRoughness->SetName(SPAIopWStringToString(iRoughness.GetName())) ;
		exchangePmiRoughness->SetIsHide(iRoughness.IsHidden()) ;
		exchangePmiRoughness->SetRoughnessObtentionType(PMI::Helper::ToRoughnessObtentionType(iRoughness.GetRoughnessObtention())) ;
		exchangePmiRoughness->SetRoughnessApplicabilityType(PMI::Helper::ToRoughnessApplicabilityType(iRoughness.GetRoughnessApplicability())) ;
		int nbFields = iRoughness.GetRoughnessFieldCount();
		for (int ii = 0; ii < nbFields; ii++)
		{
			SPAIopWString fieldValue = iRoughness.GetRoughnessFieldAt(ii);
			exchangePmiRoughness->AddRoughnessField(SPAIopWStringToString(fieldValue)) ;
		}
#if 0
        ProcessAnnotationBasicData(iRoughness);

		SPAIopPMIRoughnessObtentionType obtentionType = iRoughness.GetRoughnessObtention();
		SPAIopWString obtType;
		ToString(obtentionType, obtType);
		//LOGGER_DEBUG(" Obtention Type = %ls \n", ( const wchar_t*)obtType);
		const wchar_t *pObtTypeArray = NULL;
		obtType.ToWChar(pObtTypeArray);
		LOGGER_DEBUG(" Obtention Type = {} \n", wstring_to_utf8(pObtTypeArray));

		SPAIopPMIRoughnessApplicabilityType applicabilityType = iRoughness.GetRoughnessApplicability();
		SPAIopWString appType;
		ToString(applicabilityType, appType);
		//LOGGER_DEBUG(" Applicability Type = %ls \n", ( const wchar_t*)appType);
		const wchar_t *pAppTypeArray = NULL;
		appType.ToWChar(pAppTypeArray);
		LOGGER_DEBUG(" Applicability Type = {} \n", wstring_to_utf8(pAppTypeArray));

		int nbFields = iRoughness.GetRoughnessFieldCount();
		LOGGER_DEBUG(" Roughness Field Count = {} \n", nbFields);

		int ii = 0;
		for (ii = 0; ii < nbFields; ii++)
		{
			SPAIopWString fieldValue = iRoughness.GetRoughnessFieldAt(ii);
			//LOGGER_DEBUG(" Field_%d Value = %ls \n", ii, ( const wchar_t*)fieldValue);		
			const wchar_t *pFieldValueArray = NULL;
			fieldValue.ToWChar(pFieldValueArray);
			LOGGER_DEBUG(" Field_{} Value = {} \n", ii, wstring_to_utf8(pFieldValueArray));
		}
#endif
		ProcessAnnotationDisplay(iRoughness);
		ProcessLinkedEntities(iRoughness, oPMIInfos,exchangePmiRoughness);
    }

	std::shared_ptr<PMI::PMIInterOpDatum> ProcessDatum(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatum& iDatum, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::PMIInterOpDatum> exchangePmiDatum = std::make_shared<PMI::PMIInterOpDatum>() ;
		exchangePmiDatum->SetId(SPAIopWStringToString(iDatum.GetID())) ;
		exchangePmiDatum->SetName(SPAIopWStringToString(iDatum.GetName())) ;
		exchangePmiDatum->SetIsHide(iDatum.IsHidden()) ;
		exchangePmiDatum->SetLabel(SPAIopWStringToString(iDatum.GetLabel())) ;
		SPAIopPMIDatumTargetIter targetIter = iDatum.GetDatumTargetIterator();
		while (targetIter.Next())
		{
			SPAIopPMIDatumTarget& target = targetIter.Current();
			auto exchangeDatumTarget = ProcessDatumTarget(oPMIInfos,target, iMappingData) ;
			exchangePmiDatum->AddDatumTarget(exchangeDatumTarget) ;
		}
#if 0
		ProcessAnnotationBasicData(iDatum);

		SPAIopWString datumLabel = iDatum.GetLabel();
		//PrintMessage( L" Datum Label = \"%ls\" \n", ( const wchar_t*)datumLabel);
		const wchar_t *pDatumLabelArray = NULL;
		datumLabel.ToWChar(pDatumLabelArray);
		LOGGER_DEBUG(" Datum Label = \"{}\" \n", wstring_to_utf8(pDatumLabelArray));
		LOGGER_DEBUG(" DatumTargets: \n");
		SPAIopPMIDatumTargetIter targetIter = iDatum.GetDatumTargetIterator();
		int iTarget = 0;
		while (targetIter.Next())
		{
			SPAIopPMIDatumTarget& target = targetIter.Current();
			ProcessDatumTarget(target, iMappingData);
			iTarget++;
		}
		if (iTarget == 0)
		{
			LOGGER_DEBUG(" \t\t No Datum Target. \n");
		}
#endif
		ProcessAnnotationDisplay(iDatum);
		// ProcessLinkedEntities(iDatum, iMappingData);
		ProcessLinkedEntities(iDatum,oPMIInfos,exchangePmiDatum) ;
		return exchangePmiDatum ;
    }

	std::shared_ptr<PMI::InterOpPMIDatumTarget> ProcessDatumTarget(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatumTarget& iDatumTarget, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::InterOpPMIDatumTarget> exchangeDatumTarget = std::make_shared<PMI::InterOpPMIDatumTarget>();
		exchangeDatumTarget->SetId(SPAIopWStringToString(iDatumTarget.GetID())) ;
		exchangeDatumTarget->SetName(SPAIopWStringToString(iDatumTarget.GetName())) ;
		exchangeDatumTarget->SetIsHide(iDatumTarget.IsHidden()) ;
		exchangeDatumTarget->SetLabel(SPAIopWStringToString(iDatumTarget.GetLabel())) ;
		SPAIopPMIDatumTargetType datumTargetType;
		SPAIopWString lowerText, upperText;
		bool hasDiameter = false;
		float position1[3], position2[3];
		iDatumTarget.GetInfo(datumTargetType, hasDiameter, upperText, lowerText, position1, position2);
		exchangeDatumTarget->SetTargetType(PMI::Helper::ToDatumTargetType(datumTargetType)) ;
		exchangeDatumTarget->SetHasDiameter(hasDiameter) ;
		exchangeDatumTarget->SetUpperText(SPAIopWStringToString(upperText)) ;
		exchangeDatumTarget->SetLowerText(SPAIopWStringToString(lowerText)) ;
		exchangeDatumTarget->SetPosition1(position1[0], position1[1], position1[2]) ;
		exchangeDatumTarget->SetPosition2(position2[0], position2[1], position2[2]) ;
#if 0
		ProcessAnnotationBasicData(iDatumTarget);

		SPAIopWString datumTargetLabel = iDatumTarget.GetLabel();
		//PrintMessage( L" DatumTarget Label = \"%ls\" \n", ( const wchar_t*)datumTargetLabel);
		const wchar_t *pDatumTargetLabelArray = NULL;
		datumTargetLabel.ToWChar(pDatumTargetLabelArray);
		LOGGER_DEBUG(" DatumTarget Label = \"{}\" \n", wstring_to_utf8(pDatumTargetLabelArray));
		SPAIopPMIDatumTargetType datumTargetType;
		SPAIopWString lowerText, upperText;
		bool hasDiameter = false;
		float position1[3], position2[3];
		iDatumTarget.GetInfo(datumTargetType, hasDiameter, upperText, lowerText, position1, position2);
		const wchar_t *pUpperTextArray = NULL;
		upperText.ToWChar(pUpperTextArray);
		const wchar_t *pLowerTextArray = NULL;
		lowerText.ToWChar(pLowerTextArray);
		LOGGER_DEBUG(" Upper Text = {} \n", wstring_to_utf8(pUpperTextArray));
		LOGGER_DEBUG(" Lower Text = {} \n", wstring_to_utf8(pLowerTextArray));
		LOGGER_DEBUG(" Orientation Position: \n");
		LOGGER_DEBUG("\t\t Poition1 = ( {}, {}, {} ) \n", position1[0], position1[1], position1[2]);
		LOGGER_DEBUG("\t\t Poition2 = ( {}, {}, {} ) \n", position2[0], position2[1], position2[2]);
#endif 
		ProcessAnnotationDisplay(iDatumTarget);
		// ProcessLinkedEntities(iDatumTarget, iMappingData);
		ProcessLinkedEntities(iDatumTarget,oPMIInfos,exchangeDatumTarget) ;
		return exchangeDatumTarget ;
    }

	void ProcessGDT(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIGDT& iGDT, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::InterOpGDT> exchangePmiGDT = std::make_shared<PMI::InterOpGDT>() ;
		exchangePmiGDT->SetId(SPAIopWStringToString(iGDT.GetID())) ;
		exchangePmiGDT->SetName(SPAIopWStringToString(iGDT.GetName())) ;	
		exchangePmiGDT->SetIsHide(iGDT.IsHidden()) ;
		SPAIopPMIToleranceType tolType;
		bool isAllAround = false;
		iGDT.GetToleranceInfo(tolType,isAllAround);
		
		exchangePmiGDT->SetToleranceType(PMI::Helper::ToToleranceType(tolType)) ;
		
		SPAIopPMIText notes;
		iGDT.GetNote(notes);
		PMI::InterOpPMIText exchangeText ;
		SPAIopWString tempNote;
		notes.GetUpperString(tempNote);
		exchangeText.SetUpperText(SPAIopWStringToString(tempNote)) ;
		notes.GetLowerString(tempNote);
		exchangeText.SetLowerText(SPAIopWStringToString(tempNote)) ;
		notes.GetBeforeString(tempNote);
		exchangeText.SetBeforeText(SPAIopWStringToString(tempNote)) ;
		notes.GetAfterString(tempNote);
		exchangeText.SetAfterText(SPAIopWStringToString(tempNote)) ;
		notes.GetPrefixString(tempNote);
		exchangeText.SetPrefixText(SPAIopWStringToString(tempNote)) ;
		notes.GetSuffixString(tempNote);
		exchangeText.SetSuffixText(SPAIopWStringToString(tempNote)) ;
		notes.GetBelowString(tempNote);
		exchangeText.SetBelowText(SPAIopWStringToString(tempNote)) ;
		exchangePmiGDT->SetNoteText(exchangeText) ;

		SPAIopPMIGDTRowIter gdtRowIter = iGDT.GetRows();
		while (gdtRowIter.Next())
		{
			SPAIopPMIGDTRow gdtRow = gdtRowIter.Current();
			PMI::InterOpGDTRow exchangeGDTRow ;
			exchangeGDTRow.SetToleranceValueType(PMI::Helper::ToToleranceValueType(gdtRow.GetModDiaType())) ;
			exchangeGDTRow.SetToleranceValue(gdtRow.GetToleranceMagnitude()) ;
			exchangeGDTRow.SetRefinementToleranceValue(gdtRow.GetRefinementTol()) ;
			exchangeGDTRow.SetRateUnit1(gdtRow.GetRateUnit1()) ;
			exchangeGDTRow.SetRateUnit2(gdtRow.GetRateUnit2()) ;

			SPAIopPMIZoneModifierIter zoneModifierIter = gdtRow.GetZoneModifierIterator();
			while (zoneModifierIter.Next())
			{
				SPAIopPMIZoneModifier zoneModifier = zoneModifierIter.Current();
				PMI::PMIZoneModifier exchangeZoneModifier ;
				exchangeZoneModifier.SetZoneModifierType(PMI::Helper::ToToleranceModifierType(zoneModifier.GetZoneModifierType())) ;
				double zoneModMagnitude = 0.0;
				if (zoneModifier.GetZoneModifierMagnitude(zoneModMagnitude)){
					// LOGGER_DEBUG(" ZoneModifier{} Type = {} Magnitude = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray), zoneModMagnitude);
					exchangeZoneModifier.SetZoneModifierMagnitudeValue(zoneModMagnitude) ;
				}
				else
				{
					// LOGGER_DEBUG(" ZoneModifier{} Type = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray));
				}

				exchangeGDTRow.AddZoneModifier(exchangeZoneModifier) ;

			}

			exchangePmiGDT->AddGDTRow(exchangeGDTRow) ;

			SPAIopPMIGDTRefFrame refFrame = gdtRow.GetRefFrame();
			std::shared_ptr<PMI::GDTRefFrame> frame = ProcessGDTRefFrame(oPMIInfos,refFrame);
			exchangeGDTRow.SetGDTRefFrame(frame) ;
		}
#if 0
		ProcessAnnotationBasicData(iGDT);

		// Basic tolerance info
		SPAIopPMIToleranceType tolType;
		bool isAllAround = false;

		//aak3
		SPAIopPMIText notes;
		iGDT.GetNote(notes);
		SPAIopWString tempNote;

		//upper
		notes.GetUpperString(tempNote);
		const wchar_t* pTempNote = NULL;
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" Upper Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		//lower
		notes.GetLowerString(tempNote);
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" Lower Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		//before
		notes.GetBeforeString(tempNote);
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" Before Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		//after
		notes.GetAfterString(tempNote);
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" After Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		//prefix
		notes.GetPrefixString(tempNote);
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" Prefix Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		//suffix
		notes.GetSuffixString(tempNote);
		tempNote.ToWChar(pTempNote);
		LOGGER_DEBUG(" Suffix Tolerance Note = {} \n", wstring_to_utf8(pTempNote));

		iGDT.GetToleranceInfo(tolType, isAllAround);
		SPAIopWString sTolType;
		ToString(tolType, sTolType);
		//PrintMessage( L" Tolerance Type = %ls \n", ( const wchar_t*)sTolType);
		const wchar_t* pSTolTypeArray = NULL;
		sTolType.ToWChar(pSTolTypeArray);
		LOGGER_DEBUG(" Tolerance Type = {} \n", wstring_to_utf8(pSTolTypeArray));
		SPAIopWString allAroundStr((isAllAround) ? L"TRUE" : L"FALSE");
		const wchar_t* pAllAroundStrArray = NULL;
		allAroundStr.ToWChar(pAllAroundStrArray);
		LOGGER_DEBUG(" AllAround = {} \n", wstring_to_utf8(pAllAroundStrArray));

		int gdtRowCount = 0;
		SPAIopPMIGDTRowIter gdtRowIter = iGDT.GetRows();
		while (gdtRowIter.Next())
		{
			gdtRowCount++;
			SPAIopPMIGDTRow gdtRow = gdtRowIter.Current();

			LOGGER_DEBUG(" GDT Row {} Information: \n", gdtRowCount);
			SPAIopWString sTolValType;
			ToString(gdtRow.GetModDiaType(), sTolValType);
			//PrintMessage( L" Tolerance Value Type = %ls \n", ( const wchar_t*)sTolValType);
			const wchar_t* pSTolValTypeArray = NULL;
			sTolValType.ToWChar(pSTolValTypeArray);
			LOGGER_DEBUG(" Tolerance Value Type = {} \n", wstring_to_utf8(pSTolValTypeArray));

			LOGGER_DEBUG(" Tolerance Value = {} \n", gdtRow.GetToleranceMagnitude());
			LOGGER_DEBUG(" Refine Tolerance = {} \n", gdtRow.GetRefinementTol());
			LOGGER_DEBUG(" RateUnit1 = {} \n", gdtRow.GetRateUnit1());
			LOGGER_DEBUG(" RateUnit2 = {} \n", gdtRow.GetRateUnit2());

			// Zone Modifier
			SPAIopPMIZoneModifierIter zoneModifierIter = gdtRow.GetZoneModifierIterator();
			int nZoneModifierCounter = 0;
			while (zoneModifierIter.Next())
			{
				nZoneModifierCounter++;
				SPAIopPMIZoneModifier zoneModifier = zoneModifierIter.Current();


				SPAIopWString sZoneMod;
				ToString(zoneModifier.GetZoneModifierType(), sZoneMod);
				const wchar_t* pSZoneModArray = NULL;
				sZoneMod.ToWChar(pSZoneModArray);
				double zoneModMagnitude = 0.0;
				if (zoneModifier.GetZoneModifierMagnitude(zoneModMagnitude))
					LOGGER_DEBUG(" ZoneModifier{} Type = {} Magnitude = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray), zoneModMagnitude);
				else
					LOGGER_DEBUG(" ZoneModifier{} Type = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray));
			}

			// Reference frame
			LOGGER_DEBUG(" RefFrame: \n");
			SPAIopPMIGDTRefFrame refFrame = gdtRow.GetRefFrame();
			ProcessGDTRefFrame(refFrame);

		}
#endif
		ProcessAnnotationDisplay(iGDT);
		// ProcessLinkedEntities(iGDT, iMappingData);
		ProcessLinkedEntities(iGDT,oPMIInfos,exchangePmiGDT) ;

    }

	std::shared_ptr<PMI::GDTRefFrame> ProcessGDTRefFrame(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIGDTRefFrame& iGDTRefFrame)
    {
		std::shared_ptr<PMI::GDTRefFrame> exchangeGDTRefFrame = std::make_shared<PMI::GDTRefFrame>();
		exchangeGDTRefFrame->SetLabel(SPAIopWStringToString(iGDTRefFrame.GetLabel())) ;
		SPAIopPMIDatumRefIter datumRefIter = iGDTRefFrame.GetDatumRefIterator();
		while (datumRefIter.Next())
		{
			SPAIopPMIDatumRef datumRef = datumRefIter.Current();
			std::shared_ptr<PMI::DatumRef> exchangeDatumRef = ProcessDatumRef(oPMIInfos,datumRef);
			exchangeGDTRefFrame->AddDatumRef(exchangeDatumRef) ;
		}
#if 0
		SPAIopWString refFrameLabel = iGDTRefFrame.GetLabel();
		//PrintMessage( L"\t RefFrame Label = %ls \n", ( const wchar_t*)refFrameLabel);
		const wchar_t *pRefFrameLabelArray = NULL;
		refFrameLabel.ToWChar(pRefFrameLabelArray);
		LOGGER_DEBUG("\t RefFrame Label = {} \n", wstring_to_utf8(pRefFrameLabelArray));

		SPAIopPMIDatumRefIter datumRefIter = iGDTRefFrame.GetDatumRefIterator();
		int iDatumRef = 0;
		while (datumRefIter.Next())
		{
			SPAIopPMIDatumRef datumRef = datumRefIter.Current();
			ProcessDatumRef(datumRef);
		}
#endif 
		return exchangeGDTRefFrame ;
    }

	std::shared_ptr<PMI::DatumRef> ProcessDatumRef(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDatumRef& iDatumRef)
    {
		std::shared_ptr<PMI::DatumRef> exchangeDatumRef = std::make_shared<PMI::DatumRef>() ;
		exchangeDatumRef->SetLabel(SPAIopWStringToString(iDatumRef.GetLabel())) ;
		SPAIopPMIText  datumRefText = iDatumRef.GetText();
		PMI::InterOpPMIText exchangeText ;
		SPAIopWString tempIopString ;
		datumRefText.GetUpperString(tempIopString);
		exchangeText.SetUpperText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetLowerString(tempIopString);
		exchangeText.SetLowerText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetBeforeString(tempIopString);
		exchangeText.SetBeforeText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetAfterString(tempIopString);
		exchangeText.SetAfterText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetPrefixString(tempIopString);
		exchangeText.SetPrefixText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetSuffixString(tempIopString);
		exchangeText.SetSuffixText(SPAIopWStringToString(tempIopString)) ;
		datumRefText.GetBelowString(tempIopString);
		exchangeText.SetBelowText(SPAIopWStringToString(tempIopString)) ;
		
		exchangeDatumRef->SetText(exchangeText) ;

		SPAIopPMIModifiedDatumIter modifiedDatumIter = iDatumRef.GetModifiedDatums();
		while (modifiedDatumIter.Next())
		{
			PMI::PMIModifiedDatum exchangePmiModifierDatum ;
			
			SPAIopPMIModifiedDatum modifiedDatum = modifiedDatumIter.Current();
			SPAIopPMIToleranceModifier modifier = SPAIopPMI_NoModifier;
			SPAIopPMIZoneModifierIter zoneModIter = modifiedDatum.GetZoneModifierIterator();
			
			// int zoneModCount = 0;
			while (zoneModIter.Next())
			{	
				SPAIopPMIZoneModifier zoneModifier = zoneModIter.Current();
				SPAIopPMIToleranceModifier modifier = zoneModifier.GetZoneModifierType();

				PMI::PMIZoneModifier exchangeZoneModifier ;
				exchangeZoneModifier.SetZoneModifierType(PMI::Helper::ToToleranceModifierType(modifier)) ;
				double zoneModMagnitude = 0.0;
				if (zoneModifier.GetZoneModifierMagnitude(zoneModMagnitude)){
					// LOGGER_DEBUG(" ZoneModifier{} Type = {} Magnitude = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray), zoneModMagnitude);
					exchangeZoneModifier.SetZoneModifierMagnitudeValue(zoneModMagnitude) ;
				}
				else
				{
					// LOGGER_DEBUG(" ZoneModifier{} Type = {} \n", nZoneModifierCounter, wstring_to_utf8(pSZoneModArray));
				}
				exchangePmiModifierDatum.AddZoneModifier(exchangeZoneModifier) ;
				// zoneModCount++;
			}

			// if (0 == zoneModCount) {
			// 	SPAIopPMIToleranceModifier modifier = SPAIopPMI_NoModifier;
				
			// }
			exchangeDatumRef->AddModifierDatum(exchangePmiModifierDatum) ;
			SPAIopPMIDatum datum = modifiedDatum.GetDatum();
			// std::shared_ptr<PMIInterOpDatum> exchangeDatum = ProcessDatum(datum,)
			//
		}
#if 0
		SPAIopWString datumReflabel = iDatumRef.GetLabel();
		//PrintMessage( L"\t\t DREF Label = %ls \n", ( const wchar_t*)datumReflabel);
		const wchar_t *pDatumReflabelArray = NULL;
		datumReflabel.ToWChar(pDatumReflabelArray);
		LOGGER_DEBUG("\t\t DREF Label = {} \n", wstring_to_utf8(pDatumReflabelArray));
		SPAIopPMIText  datumRefText = iDatumRef.GetText();
		SPAIopWString datumRefTextStr; 
		datumRefText.GetAfterString(datumRefTextStr);
		const wchar_t* pDatumRefTextArray = NULL;
		datumRefTextStr.ToWChar(pDatumRefTextArray);
		LOGGER_DEBUG("\t\t\t DREF Text = {} \n", wstring_to_utf8(pDatumRefTextArray));
		SPAIopPMIModifiedDatumIter modifiedDatumIter = iDatumRef.GetModifiedDatums();
		int iModDatum = 0;
		while (modifiedDatumIter.Next())
		{
			SPAIopPMIModifiedDatum modifiedDatum = modifiedDatumIter.Current();
			SPAIopPMIToleranceModifier modifier = SPAIopPMI_NoModifier;
			SPAIopPMIZoneModifierIter zoneModIter = modifiedDatum.GetZoneModifierIterator();
			int zoneModCount = 0;
			while (zoneModIter.Next())
			{
				zoneModCount++;
				SPAIopPMIZoneModifier zoneModifier = zoneModIter.Current();
				SPAIopPMIToleranceModifier modifier = zoneModifier.GetZoneModifierType();

				SPAIopWString sModifier;
				ToString(modifier, sModifier);
				const wchar_t* pSModifierArray = NULL;
				sModifier.ToWChar(pSModifierArray);
				LOGGER_DEBUG("\t\t\t Datum Modifier{} Type = {} \n", zoneModCount, wstring_to_utf8(pSModifierArray));

				double zoneModifierMagnitude = 0.0;
				bool containsMagnitude = zoneModifier.GetZoneModifierMagnitude(zoneModifierMagnitude);

				if (containsMagnitude)
					LOGGER_DEBUG("\t\t\t Datum Modifier{} Magnitude = {} \n", zoneModCount, zoneModifierMagnitude);
			}
			if (zoneModCount == 0)
			{
				SPAIopPMIToleranceModifier modifier = SPAIopPMI_NoModifier;
				SPAIopWString sModifier;
				ToString(modifier, sModifier);
				const wchar_t* pSModifierArray = NULL;
				sModifier.ToWChar(pSModifierArray);
				LOGGER_DEBUG("\t\t\t Datum Modifier = {} \n", wstring_to_utf8(pSModifierArray));
			}

			SPAIopPMIDatum datum = modifiedDatum.GetDatum(); // Process Datum if you want( if not alrady Processed).
			SPAIopWString datumName(L"Unknown");
			datumName = datum.GetName();
			SPAIopWString datumId = datum.GetID();
			SPAIopWString sModifier;
			ToString(modifier, sModifier);

			//PrintMessage( L"\t\t\t Datum Name = %ls, Id = %ls \n", ( const wchar_t*)datumName, ( const wchar_t*)datumId);
			const wchar_t * pDatumNameArray = NULL;
			const wchar_t * pDatumIdArray = NULL;
			datumName.ToWChar(pDatumNameArray);
			datumId.ToWChar(pDatumIdArray);
			LOGGER_DEBUG("\t\t\t Datum Name = {}, Id = {} \n", wstring_to_utf8(pDatumNameArray), wstring_to_utf8(pDatumIdArray));
		}
#endif
		return exchangeDatumRef ;
    }

	void ProcessDimension(std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,SPAIopPMIDimension& iDimension, SPAIopMappingData& iMappingData)
    {
		std::shared_ptr<PMI::InterOpPMIDimension> exchangePMIDimension  = std::make_shared<PMI::InterOpPMIDimension>() ;
		exchangePMIDimension->SetId(SPAIopWStringToString(iDimension.GetID())) ;
		exchangePMIDimension->SetIsHide(iDimension.IsHidden()) ;
		exchangePMIDimension->SetName(SPAIopWStringToString(iDimension.GetName())) ;
		SPAIopPMIDimensionMainType dimMainType;
		SPAIopPMIDimensionSubType dimSubType;
		SPAIopPMICalloutFeatureAnnotationType calloutFeatureAnnotType;
		iDimension.GetType(dimMainType, dimSubType, calloutFeatureAnnotType);
		exchangePMIDimension->SetMainType(PMI::Helper::ToDimensionMainType(dimMainType)) ;
		exchangePMIDimension->SetSubType(PMI::Helper::ToDimensionSubType(dimSubType)) ;
		exchangePMIDimension->SetCalloutFeatureAnnotationType(PMI::Helper::ToCalloutFeatureAnnotationType(calloutFeatureAnnotType)) ;
		exchangePMIDimension->SetIsDriving(iDimension.IsDriving()) ;
		if (SPAIopPMI_DMT_CoordDim == dimMainType)
		{
			double x, y, z;
			iDimension.GetCoordValue(x, y, z);
			exchangePMIDimension->SetCoordValue(x, y, z) ;
		}
		else
		{
			double value, precision;
			SPAIopPMIUnit unit;
			iDimension.GetValue(value, unit, precision);
			exchangePMIDimension->SetDimensionValue(value) ;
			exchangePMIDimension->SetUnit(PMI::Helper::ToUnit(unit)) ;
			exchangePMIDimension->SetTolerancePrecisionValue(precision) ;
		}

		double lowerValue, upperValue;
		if (true == iDimension.GetNumericalTolerances(upperValue, lowerValue))
		{
			exchangePMIDimension->SetToleranceNumerialLowerValue(lowerValue)  ;
			exchangePMIDimension->SetToleranceNumerialUpperValue(upperValue)  ;
		}

		SPAIopWString upperText, lowerText;
		if (true == iDimension.GetAlphanumericalTolerances(upperText, lowerText))
		{
			exchangePMIDimension->SetToleranceAlphanumericalLowerValue(SPAIopWStringToString(lowerText)) ;
			exchangePMIDimension->SetToleranceAlphanumericalUpperValue(SPAIopWStringToString(upperText)) ;
		}

		double fakeVal;
		if (true == iDimension.GetFakeNumericalValue(fakeVal))
		{
			exchangePMIDimension->SetNumbericalFakeValue(fakeVal)  ;
		}

		SPAIopWString fakeValStr;
		if (true == iDimension.GetFakeAlphanumericalValue(fakeValStr))
		{
			exchangePMIDimension->SetAlphanumericalFakeValue(SPAIopWStringToString(fakeValStr)) ;
		}

		SPAIopPMIText notes;
		iDimension.GetNote(notes);
		PMI::InterOpPMIText exchangeNote ;
		SPAIopWString tempNote;
		notes.GetUpperString(tempNote);
		exchangeNote.SetUpperText(SPAIopWStringToString(tempNote)) ;
		notes.GetUpperString(tempNote);
		exchangeNote.SetUpperText(SPAIopWStringToString(tempNote)) ;
		notes.GetLowerString(tempNote);
		exchangeNote.SetLowerText(SPAIopWStringToString(tempNote)) ;
		notes.GetBeforeString(tempNote);
		exchangeNote.SetBeforeText(SPAIopWStringToString(tempNote)) ;
		notes.GetAfterString(tempNote);
		exchangeNote.SetAfterText(SPAIopWStringToString(tempNote)) ;
		notes.GetPrefixString(tempNote);
		exchangeNote.SetPrefixText(SPAIopWStringToString(tempNote)) ;
		notes.GetSuffixString(tempNote);
		exchangeNote.SetSuffixText(SPAIopWStringToString(tempNote)) ;
		notes.GetBelowString(tempNote);
		exchangeNote.SetBelowText(SPAIopWStringToString(tempNote)) ;
		exchangePMIDimension->SetNote(exchangeNote) ;

		SPAIopPMIAnnotationView view = iDimension.GetView();
		float origin[3], uDir[3], vDir[3];
		bool isViewPlaneDefined = view.GetAxis(origin, uDir, vDir);

		if (isViewPlaneDefined)
		{
			float lineStart[2], lineEnd[2];
			SPAIopPMIArrowSymbol lineSymbolStart, lineSymbolEnd;
			bool isSymbolOutside;
			iDimension.GetDimensionLine(lineStart, lineEnd, lineSymbolStart, lineSymbolEnd, isSymbolOutside);
			exchangePMIDimension->SetLine2dStart(lineStart[0], lineStart[1]) ;
			exchangePMIDimension->SetLine2dEnd(lineEnd[0], lineEnd[1]) ;
			exchangePMIDimension->SetLine2dSymbolStart(PMI::Helper::ToArrowSymbol(lineSymbolStart)) ;
			exchangePMIDimension->SetLine2dSymbolEnd(PMI::Helper::ToArrowSymbol(lineSymbolEnd)) ;
		}
#if 0
		ProcessAnnotationBasicData(iDimension);

		// Dimension type
		SPAIopPMIDimensionMainType dimMainType;
		SPAIopPMIDimensionSubType dimSubType;
		SPAIopPMICalloutFeatureAnnotationType calloutFeatureAnnotType;
		iDimension.GetType(dimMainType, dimSubType, calloutFeatureAnnotType);

		SPAIopWString sDimMainType;
		ToString(dimMainType, sDimMainType);
		//PrintMessage( L" Dimension MainType = %ls \n", ( const wchar_t*)sDimMainType);
		const wchar_t *pSDimMainTypeArray = NULL;
		sDimMainType.ToWChar(pSDimMainTypeArray);
		LOGGER_DEBUG(" Dimension MainType = {} \n", wstring_to_utf8(pSDimMainTypeArray));

		SPAIopWString sDimSubType;
		ToString(dimSubType, sDimSubType);
		//PrintMessage( L" Dimension SubType = %ls \n", ( const wchar_t*)sDimSubType);
		const wchar_t *pSDimSubTypeArray = NULL;
		sDimSubType.ToWChar(pSDimSubTypeArray);
		LOGGER_DEBUG(" Dimension SubType = {} \n", wstring_to_utf8(pSDimSubTypeArray));

		if(calloutFeatureAnnotType != SPAIopPMI_FEATURETYPE_UNKNOWN)
		{
			SPAIopWString sCallOutFeatType;
			ToString(calloutFeatureAnnotType, sCallOutFeatType);
			const wchar_t *pCallOutFeatType = NULL;
			sCallOutFeatType.ToWChar(pCallOutFeatType);
			LOGGER_DEBUG(" Callout Feature Annotation Type = {} \n", wstring_to_utf8(pCallOutFeatType));
		}

		// Driving flag (whether the dimension value drives geometry)
		bool isDrivingDim = iDimension.IsDriving();
		SPAIopWString drivingDimFlag((isDrivingDim) ? L"TRUE" : L"FALSE");
		//PrintMessage( L" Driving Dimension = %ls \n", ( const wchar_t*)drivingDimFlag);
		const wchar_t *pDrivingDimFlagArray = NULL;
		drivingDimFlag.ToWChar(pDrivingDimFlagArray);
		LOGGER_DEBUG(" Driving Dimension = {} \n", wstring_to_utf8(pDrivingDimFlagArray));

		// Dimension value
		if (SPAIopPMI_DMT_CoordDim == dimMainType)
		{
			double x, y, z;
			iDimension.GetCoordValue(x, y, z);
			LOGGER_DEBUG(" Dimension Value = ( {}, {}, {} ) \n", x, y, z);
		}
		else
		{
			double value, precision;
			SPAIopPMIUnit unit;
			iDimension.GetValue(value, unit, precision);
			SPAIopWString sUnit;
			ToString(unit, sUnit);
			//PrintMessage( L" Dimension Value = %f, Unit = %ls, Precision = %f \n", value, ( const wchar_t*)sUnit, precision);
			const wchar_t *pSUnitArray = NULL;
			sUnit.ToWChar(pSUnitArray);
			LOGGER_DEBUG(" Dimension Value = {}, Unit = {}, Precision = {} \n", value, wstring_to_utf8(pSUnitArray), precision);
		}
		// Dimension tolerances
		double lowerValue, upperValue;
		if (true == iDimension.GetNumericalTolerances(upperValue, lowerValue))
		{
			LOGGER_DEBUG(" Numerical Tolerances: Upper Value = {}, Lower Value = {} \n", upperValue, lowerValue);
		}
		SPAIopWString upperText, lowerText;
		if (true == iDimension.GetAlphanumericalTolerances(upperText, lowerText))
		{
			//PrintMessage( L" Alphanumerical Tolerances: Upper Text = %ls, Lower Text = %ls \n", ( const wchar_t*)upperText, ( const wchar_t*)lowerText);
			const wchar_t *pUpperTextArray = NULL;
			const wchar_t *pLowerTextArray = NULL;
			upperText.ToWChar(pUpperTextArray);
			lowerText.ToWChar(pLowerTextArray);
			LOGGER_DEBUG(" Alphanumerical Tolerances: Upper Text = {}, Lower Text = {} \n", wstring_to_utf8(pUpperTextArray), wstring_to_utf8(pLowerTextArray));
		}

		// Dimension fake value
		double fakeVal;
		if (true == iDimension.GetFakeNumericalValue(fakeVal))
		{
			LOGGER_DEBUG(" Numerical FakeValue = {} \n", fakeVal);
		}
		SPAIopWString fakeValStr;
		if (true == iDimension.GetFakeAlphanumericalValue(fakeValStr))
		{
			//PrintMessage( L" Alphanumerical FakeValue = %ls \n", ( const wchar_t*)fakeValStr);
			const wchar_t *pFakeValStrArray = NULL;
			fakeValStr.ToWChar(pFakeValStrArray);
			LOGGER_DEBUG(" Alphanumerical FakeValue = {} \n", wstring_to_utf8(pFakeValStrArray));
		}
		// Dimension text
		SPAIopWString prefixStr, suffixStr, beforeStr, afterStr, upperStr, lowerStr, holeCalloutDimText, belowStr;
		bool hasAssociatedTexts = false;
		SPAIopPMIText notes;
		iDimension.GetNote(notes);
		hasAssociatedTexts |= notes.GetUpperString(upperStr);
		hasAssociatedTexts |= notes.GetAfterString(afterStr);
		hasAssociatedTexts |= notes.GetLowerString(lowerStr);
		hasAssociatedTexts |= notes.GetBeforeString(beforeStr);
		hasAssociatedTexts |= notes.GetPrefixString(prefixStr);
		hasAssociatedTexts |= notes.GetSuffixString(suffixStr);
		hasAssociatedTexts |= notes.GetBelowString(belowStr);
		hasAssociatedTexts |= iDimension.GetHoleCalloutAlphanumericalValue(holeCalloutDimText);

		SPAIopWString associatedTextFlag((hasAssociatedTexts) ? L"TRUE" : L"FALSE");
		//PrintMessage( L" Associated Texts: %ls \n", ( const wchar_t*)associatedTextFlag);
		const wchar_t *pAssociatedTextFlagArray = NULL;
		associatedTextFlag.ToWChar(pAssociatedTextFlagArray);
		LOGGER_DEBUG(" Associated Texts: {} \n", wstring_to_utf8(pAssociatedTextFlagArray));
		if (true == hasAssociatedTexts)
		{
			/*PrintMessage( L"\t Prefix Text = %ls \n", ( const wchar_t*)prefixStr);
			PrintMessage( L"\t Suffix Text = %ls \n", ( const wchar_t*)suffixStr);
			PrintMessage( L"\t Before Text = %ls \n", ( const wchar_t*)beforeStr);
			PrintMessage( L"\t After Text = %ls \n", ( const wchar_t*)afterStr);
			PrintMessage( L"\t Upper Text = %ls \n", ( const wchar_t*)upperStr);
			PrintMessage( L"\t Lower Text = %ls \n", ( const wchar_t*)lowerStr);*/
			const wchar_t *pPrefixStrArray = NULL;
			const wchar_t *pSuffixStrArray = NULL;
			const wchar_t *pBeforeStrArray = NULL;
			const wchar_t *pAfterStrArray = NULL;
			const wchar_t *pUpperStrArray = NULL;
			const wchar_t *pLowerStrArray = NULL;
			const wchar_t *pHoleCalloutDimTextArray = NULL;
			const wchar_t *pBelowStrArray = NULL;
			prefixStr.ToWChar(pPrefixStrArray);
			suffixStr.ToWChar(pSuffixStrArray);
			beforeStr.ToWChar(pBeforeStrArray);
			afterStr.ToWChar(pAfterStrArray);
			upperStr.ToWChar(pUpperStrArray);
			lowerStr.ToWChar(pLowerStrArray);
			holeCalloutDimText.ToWChar(pHoleCalloutDimTextArray);
			belowStr.ToWChar(pBelowStrArray);
			LOGGER_DEBUG("\t Prefix Text = {} \n", wstring_to_utf8(pPrefixStrArray));
			LOGGER_DEBUG("\t Suffix Text = {} \n", wstring_to_utf8(pSuffixStrArray));
			LOGGER_DEBUG("\t Before Text = {} \n", wstring_to_utf8(pBeforeStrArray));
			LOGGER_DEBUG("\t After Text = {} \n", wstring_to_utf8(pAfterStrArray));
			LOGGER_DEBUG("\t Upper Text = {} \n", wstring_to_utf8(pUpperStrArray));
			LOGGER_DEBUG("\t Lower Text = {} \n", wstring_to_utf8(pLowerStrArray));
			LOGGER_DEBUG("\t Below Text = {} \n", wstring_to_utf8(pBelowStrArray));
			if (calloutFeatureAnnotType != SPAIopPMI_FEATURETYPE_UNKNOWN)
				LOGGER_DEBUG("\t Hole Callout Dim Text = {} \n", wstring_to_utf8(pHoleCalloutDimTextArray));
		}

		SPAIopPMIAnnotationView view = iDimension.GetView();
		float origin[3], uDir[3], vDir[3];
		bool isViewPlaneDefined = view.GetAxis(origin, uDir, vDir);
		if (isViewPlaneDefined)
		{
			float lineStart[2], lineEnd[2];
			SPAIopPMIArrowSymbol lineSymbolStart, lineSymbolEnd;
			bool isSymbolOutside;
			iDimension.GetDimensionLine(lineStart, lineEnd, lineSymbolStart, lineSymbolEnd, isSymbolOutside);
			LOGGER_DEBUG(" Dimension Line Extremities: \n");

			SPAIopWString sLineSymStart, sLineSymEnd;
			ToString(lineSymbolStart, sLineSymStart);
			ToString(lineSymbolEnd, sLineSymEnd);
			//PrintMessage( L"\t Start Extremity = ( %f, %f), Arrow Symbol = %ls \n", lineStart[0], lineStart[1], ( const wchar_t*)sLineSymStart);
			const wchar_t *pSLineSymStartArray = NULL;
			sLineSymStart.ToWChar(pSLineSymStartArray);
			LOGGER_DEBUG("\t Start Extremity = ( {}, {}), Arrow Symbol = {} \n", lineStart[0], lineStart[1], wstring_to_utf8(pSLineSymStartArray));
			//PrintMessage( L"\t End Extremity = ( %f, %f), Arrow Symbol = %ls \n", lineEnd[0], lineEnd[1], ( const wchar_t*)sLineSymEnd);
			const wchar_t *pSLineSymEndArray = NULL;
			sLineSymEnd.ToWChar(pSLineSymEndArray);
			LOGGER_DEBUG("\t End Extremity = ( {}, {}), Arrow Symbol = {} \n", lineEnd[0], lineEnd[1], wstring_to_utf8(pSLineSymEndArray));
		}
#endif

		ProcessAnnotationDisplay(iDimension);
		// ProcessLinkedEntities(iDimension, iMappingData);
		ProcessLinkedEntities(iDimension,oPMIInfos,exchangePMIDimension) ;
    }

	void ProcessCapture(SPAIopPMICapture& iCapture, SPAIopMappingData& iMappingData, SPAIopWString iBuffer, bool iIsToDumpFull)
    {
		//Capture Name
		SPAIopWString captureName = iCapture.GetName();
		const wchar_t *pCaptureName = NULL;
		captureName.ToWChar(pCaptureName);
		//PrintMessage( L" Capture Name = %ls \n", pCaptureName);

		SPAIopWString captureId = iCapture.GetID();
		const wchar_t *pCaptureId = NULL;
		captureId.ToWChar(pCaptureId);

		// Capture Attributes
		bool isHidden; bool isCurrent;
		SPAIopWString hiddenText;
		iCapture.GetAttributes(isHidden, isCurrent, hiddenText);

		SPAIopWString visibilityFlag((isHidden) ? L"FALSE" : L"TRUE");
		SPAIopWString activeFlag((isCurrent) ? L"TRUE" : L"FALSE");
		//PrintMessage( L" Capture Visibility = %ls, Active = %ls \n", ( const wchar_t*)visibilityFlag, ( const wchar_t*)activeFlag);
		const wchar_t *pVisibilityFlagArray = NULL;
		const wchar_t *pActiveFlagArray = NULL;
		visibilityFlag.ToWChar(pVisibilityFlagArray);
		activeFlag.ToWChar(pActiveFlagArray);

		const wchar_t *pBufferArray = NULL;
		iBuffer.ToWChar(pBufferArray);

		LOGGER_DEBUG("{} Capture Name = {}, Id = {}, Visibility = {}, Active = {} \n", 
			wstring_to_utf8(pBufferArray), 
			wstring_to_utf8(pCaptureName), 
			wstring_to_utf8(pCaptureId), 
			wstring_to_utf8(pVisibilityFlagArray), 
			wstring_to_utf8(pActiveFlagArray));

		//PrintMessage( L" Capture Visibility = %ls, Active = %ls \n",pVisibilityFlagArray,pActiveFlagArray);
		//PrintMessage( L" HiddenText =%ls \n", ( const wchar_t*)hiddenText);
		if (iIsToDumpFull)
		{
			const wchar_t *pHiddenTextArray = NULL;
			hiddenText.ToWChar(pHiddenTextArray);
			LOGGER_DEBUG(" HiddenText ={} \n", wstring_to_utf8(pHiddenTextArray));

			// Camera Properties
			SPAIopWString cameraName;
			SPAIopPMICameraType cameraType;
			float camOrigin[3], camTarget[3], camUpDirection[3];
			float camViewAngle, camZoom;
			iCapture.GetCamera(cameraName, cameraType, camOrigin, camTarget, camUpDirection, camViewAngle, camZoom);

			LOGGER_DEBUG(" CameraProperties: \n");
			//PrintMessage( L"\t Camera Name = %ls \n", ( const wchar_t*)cameraName);
			const wchar_t *pCameraNameArray = NULL;
			cameraName.ToWChar(pCameraNameArray);
			if (0 != wcscmp(pCameraNameArray, L""))
			{
				LOGGER_DEBUG("\t Camera Name = {} \n", 
					wstring_to_utf8(pCameraNameArray));

				SPAIopWString sCameraType;
				ToString(cameraType, sCameraType);
				//PrintMessage( L"\t Camera Type = %ls \n", ( const wchar_t*)sCameraType);
				const wchar_t* pSCameraTypeArray = NULL;
				sCameraType.ToWChar(pSCameraTypeArray);
				LOGGER_DEBUG("\t Camera Type = {} \n", wstring_to_utf8(pSCameraTypeArray));

				LOGGER_DEBUG("\t Camera Origin = ( {}, {}, {}) \n", camOrigin[0], camOrigin[1], camOrigin[2]);
				LOGGER_DEBUG("\t Camera Target Position = ( {}, {}, {}) \n", camTarget[0], camTarget[1], camTarget[2]);
				LOGGER_DEBUG("\t Camera View Direction Normal = ( {}, {}, {}) \n", camUpDirection[0], camUpDirection[1], camUpDirection[2]);
				LOGGER_DEBUG("\t Camera View Angle = {} \n", camViewAngle);
				LOGGER_DEBUG("\t Camera Zoom = {} \n", camZoom);
			}
			else
				LOGGER_DEBUG("\t Camera Name = None \n");

			// Clipping Plne Info
			float clipOrigin[3], clipNormal[3];
			bool hasClippingPlane = iCapture.GetClippingPlane(clipOrigin, clipNormal);

			SPAIopWString clippingPlaneInfoFlag((hasClippingPlane) ? L"Defined" : L"Not Defined");
			//PrintMessage( L" Clipping Plane Information: %ls \n", ( const wchar_t*)clippingPlaneInfoFlag);
			const wchar_t *pClippingPlaneInfoFlagArray = NULL;
			clippingPlaneInfoFlag.ToWChar(pClippingPlaneInfoFlagArray);
			LOGGER_DEBUG(" Clipping Plane Information: {} \n", wstring_to_utf8(pClippingPlaneInfoFlagArray));
			LOGGER_DEBUG("\t Clipping Plane Origin = ( {}, {}, {}) \n", clipOrigin[0], clipOrigin[1], clipOrigin[2]);
			LOGGER_DEBUG("\t Clipping Plane Normal = ( {}, {}, {}) \n", clipNormal[0], clipNormal[1], clipNormal[2]);

			SPAIopPMIAnnotationIter annotIter = iCapture.GetAnnotationIterator();
			int iAnnot = 0;
			LOGGER_DEBUG(" Capture Entities: \n");
			while (annotIter.Next())
			{
				SPAIopPMIAnnotation& annot = annotIter.Current();
				LOGGER_DEBUG("\t Annotation_Entity: \n");
				ProcessAnnotationBasicData(annot, SPAIopWString(L"\t\t"), false);
				iAnnot++;
			}
			if (0 == iAnnot)
			{
				LOGGER_DEBUG("\t No Entities are Captured. \n");
			}

			bool manageHideShowBodyState =false;
			bool manageHideShowBodyStateFound = iCapture.GetManageHideShowBodyFlag(manageHideShowBodyState);
			if(manageHideShowBodyStateFound)
			{
				SPAIopWString manageHideShowBodyFlag((manageHideShowBodyState) ? L"TRUE" : L"FALSE");
				const wchar_t* pManageHideShowFlag = NULL;
				manageHideShowBodyFlag.ToWChar(pManageHideShowFlag);
				LOGGER_DEBUG(" ManageHideShowBodyFlag = %ls \n", wstring_to_utf8(pManageHideShowFlag));
			}
			else
			{
				LOGGER_DEBUG(" ManageHideShowBodyFlag = Not Found \n");
			}

			LOGGER_DEBUG(" Constructed Geometries visually managed by Capture: \n");
			SPAIopEntityIter constGeomIter = iCapture.GetConstructedGeometryIterator();
			int constGeom = 0;
			while (constGeomIter.Next())
			{
				constGeom++;
				SPAIopEntity constGeomEntity = constGeomIter.Current();
				LOGGER_DEBUG("\t Constructed Geometry{}: \n", constGeom);
				// if (NULL != SPAIopPMIUtils::ProcessPartEntityCBFct)
				// {
				// 	SPAIopWString tabStr(L"\t\t");
				// 	SPAIopPMIUtils::ProcessPartEntityCBFct(constGeomEntity, tabStr);
				// }
				LOGGER_DEBUG("How to process this entity? ") ;
			}
			LOGGER_DEBUG("\t Total Constructed Geometries visually managed by Capture = {} \n", constGeom);

			LOGGER_DEBUG(" Bodies visually managed by Capture: \n");
			SPAIopEntityIter bodyIter = iCapture.GetBodyIterator();
			int bodyCount = 0;
			while (bodyIter.Next())
			{
				bodyCount++;
				SPAIopEntity bodyEntity = bodyIter.Current();
				LOGGER_DEBUG("\t Body{}: \n", bodyCount);
				// if (NULL != SPAIopPMIUtils::ProcessPartEntityCBFct)
				// {
				// 	SPAIopWString tabStr(L"\t\t");
				// 	SPAIopPMIUtils::ProcessPartEntityCBFct(bodyEntity, tabStr);
				// }
				LOGGER_DEBUG("How to process this entity? ") ;
			}
			LOGGER_DEBUG("\t Total Bodies visually managed by Capture = {} \n", bodyCount);
		}
    }

	void ProcessAnnotationBasicData(SPAIopPMIAnnotation& iAnnotation, SPAIopWString iBuffer, bool iIsToDumpFull)
    {
        SPAIopPMIAnnotationType annotType = iAnnotation.GetType();
		SPAIopWString sAnnotType;
		ToString(annotType, sAnnotType);
		SPAIopWString annotName = iAnnotation.GetName();
		SPAIopWString annotId = iAnnotation.GetID();
		bool isHidden = iAnnotation.IsHidden();
		SPAIopWString visibleStr((isHidden) ? L"FALSE" : L"TRUE");
		//PrintMessage( L"%ls Annotation Type = %ls, Name = %ls, Id = %ls, Visibility = %ls \n", ( const wchar_t*)iBuffer, ( const wchar_t*)sAnnotType, ( const wchar_t*)annotName, ( const wchar_t*)annotId, ( const wchar_t*)visibleStr);
		const wchar_t *pIBufferArray = NULL;
		const wchar_t *pSAnnotTypeArray = NULL;
		const wchar_t *pAnnotNameArray = NULL;
		const wchar_t *pAnnotIdArray = NULL;
		const wchar_t *pVisibleStrArray = NULL;

		iBuffer.ToWChar(pIBufferArray);
		sAnnotType.ToWChar(pSAnnotTypeArray);
		annotName.ToWChar(pAnnotNameArray);
		annotId.ToWChar(pAnnotIdArray);
		visibleStr.ToWChar(pVisibleStrArray);

		if (true == iIsToDumpFull)
			LOGGER_DEBUG("{} Annotation Type = {}, Name = {}, Id = {}, Visibility = {} \n", 
				wstring_to_utf8(pIBufferArray), 
				wstring_to_utf8(pSAnnotTypeArray), 
				wstring_to_utf8(pAnnotNameArray), 
				wstring_to_utf8(pAnnotIdArray), 
				wstring_to_utf8(pVisibleStrArray));
		else
			LOGGER_DEBUG("{} Annotation Type = {}, Name = {}, Id = {} \n", 
				wstring_to_utf8(pIBufferArray), 
				wstring_to_utf8(pSAnnotTypeArray), 
				wstring_to_utf8(pAnnotNameArray), 
				wstring_to_utf8(pAnnotIdArray));
    }

	void ProcessAnnotationViewData(SPAIopPMIAnnotationView& iAnnotationView, SPAIopWString iBuffer, bool iIsToDumpFull)
    {
		SPAIopWString annotViewName = iAnnotationView.GetName();
		SPAIopWString annotViewId = iAnnotationView.GetID();
		bool isHidden = iAnnotationView.IsHidden();
		SPAIopWString visibleStr((isHidden) ? L"FALSE" : L"TRUE");

		const wchar_t *pIBufferArray = NULL;
		const wchar_t *pAnnotViewNameArray = NULL;
		const wchar_t *pAnnotViewIdArray = NULL;
		const wchar_t *pVisibleStrArray = NULL;

		iBuffer.ToWChar(pIBufferArray);
		annotViewName.ToWChar(pAnnotViewNameArray);
		annotViewId.ToWChar(pAnnotViewIdArray);
		visibleStr.ToWChar(pVisibleStrArray);

		if (true == iIsToDumpFull)
			LOGGER_DEBUG("{} AnnotationView Name = {}, Id = {}, Visibility = {} \n", 
				wstring_to_utf8(pIBufferArray), 
				wstring_to_utf8(pAnnotViewNameArray), 
				wstring_to_utf8(pAnnotViewIdArray), 
				wstring_to_utf8(pVisibleStrArray));
		else
			LOGGER_DEBUG("{} AnnotationView Name = {}, Id = {} \n", 
				wstring_to_utf8(pIBufferArray), 
				wstring_to_utf8(pAnnotViewNameArray), 
				wstring_to_utf8(pAnnotViewIdArray));
    }

	const double min_float_tol = 5.0e-07;
	static inline double ChangeMinus0(const double& value)
	{
		return std::fabs(value) < min_float_tol ? 0.0 : value;
	}

	void ProcessAnnotationDisplay(SPAIopPMIAnnotation& iAnnotation)
    {
		#if 0
		LOGGER_DEBUG("\n Annotation Display Info: \n");

		// View
		SPAIopPMIAnnotationView view = iAnnotation.GetView();
		float origin[3] = {0.0f, 0.0f, 0.0f};
		float uDir[3] = {0.0f, 0.0f, 0.0f};
		float vDir[3] = {0.0f, 0.0f, 0.0f};

		bool isViewPlaneDefined = view.GetAxis( origin, uDir, vDir);
		SPAIopWString planeDefined( (isViewPlaneDefined) ? L"Plane Defined" : L"Plane UnDefined");
		//LOGGER_DEBUG("\t View : %ls \n", ( const wchar_t*)planeDefined);
		const wchar_t *pPlaneDefinedArray = NULL;
		planeDefined.ToWChar(pPlaneDefinedArray);
		LOGGER_DEBUG("\t View : {} \n",wstring_to_utf8(pPlaneDefinedArray));
		if( true == isViewPlaneDefined)
		{
			LOGGER_DEBUG("\t\t Origin = ({},{},{} ) \n", ChangeMinus0(origin[0]), ChangeMinus0(origin[1]), ChangeMinus0(origin[2]));
			LOGGER_DEBUG("\t\t UDirection = ({},{},{} ) \n", ChangeMinus0(uDir[0]), ChangeMinus0(uDir[1]), ChangeMinus0(uDir[2]));
			LOGGER_DEBUG("\t\t VDirection = ({},{},{} ) \n", ChangeMinus0(vDir[0]), ChangeMinus0(vDir[1]), ChangeMinus0(vDir[2]));
		}

		// Annotation positioning information
		float position[2] = { 0.0f, 0.0f};
		float angle = 0.0f;
		float zDepth = 0.0f;
		SPAIopPMIOrientation orientation;
		bool isPositionDefined = iAnnotation.GetPositioning( position, orientation, angle, zDepth);

		SPAIopWString positionDefined( (isPositionDefined) ? L"Defined" : L"UnDefined");
		//LOGGER_DEBUG("\t Annotation positioning in View : %ls \n", ( const wchar_t*)positionDefined);
		const wchar_t *pPositionDefinedArray = NULL;
		positionDefined.ToWChar(pPositionDefinedArray);
		LOGGER_DEBUG("\t Annotation positioning in View : {} \n",wstring_to_utf8(pPositionDefinedArray));
		if( isPositionDefined )
		{
			LOGGER_DEBUG("\t\t Position = ( {}, {} ) \n", position[0], position[1]);
			SPAIopWString sOrientation;
			ToString( orientation, sOrientation);
			//LOGGER_DEBUG("\t\t Orientation = %ls \n", ( const wchar_t*)sOrientation);
			const wchar_t *pSOrientationArray = NULL;
			sOrientation.ToWChar(pSOrientationArray);
			LOGGER_DEBUG("\t\t Orientation =  \n",wstring_to_utf8(pSOrientationArray));
			LOGGER_DEBUG("\t\t Angle = {} \n", angle);
			LOGGER_DEBUG("\t\t ZDepth = {} \n", zDepth);
		}

		// Leadr Info
		LOGGER_DEBUG("\t Leader Info: \n");
		SPAIopPMILeaderIter leaderIter = iAnnotation.GetLeaderIterator();
		int iLeader=0;
		while( leaderIter.Next())
		{
			SPAIopPMILeader leader = leaderIter.Current();
			int nbPoints = leader.GetPointCount();
			float ptHead[3] = { 0.0f, 0.0f,0.0f};
			float ptTail[3] = { 0.0f, 0.0f,0.0f};
			bool isMultiLineLeader=leader.Get3DPoint(0, ptTail[0], ptTail[1], ptTail[2]);
			isMultiLineLeader =leader.Get3DPoint(nbPoints - 1, ptHead[0], ptHead[1], ptHead[2]);
			if (!isMultiLineLeader)
			{
				leader.GetPoint( 0, ptTail[0], ptTail[1]);
				leader.GetPoint( nbPoints-1, ptHead[0], ptHead[1]); 
				LOGGER_DEBUG("\t\t Leader Line #{}	Head Point = ( {}, {}), Tail Point = ( {}, {}) \n", iLeader, ptHead[0], ptHead[1], ptTail[0], ptTail[1]);
			}
			else
			{
				LOGGER_DEBUG("\t\t Leader Line #{}	Head Point = ( {}, {},{}), Tail Point = ( {}, {},{}) \n", iLeader, ptHead[0], ptHead[1], ptHead[2], ptTail[0], ptTail[1], ptTail[2]);
			}
			
			iLeader++;
		}
		#endif
    }

	// void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation, SPAIopMappingData& iMappingData,SPAIopWString iBuffer)
    // {
	// 	// ProcessLinkedEntities( iAnnotation, iMappingData, _inputPSReferenceName,iBuffer);
	// 	ProcessLinkedEntities( iAnnotation,{},NULL);
    // }

	// void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation, SPAIopMappingData& iMappingData,const SPAIopWString& iPSReferenceName, const SPAIopWString& iBuffer)
	void ProcessLinkedEntities(SPAIopPMIAnnotation& iAnnotation,std::unordered_map<std::string ,PMI::InterOpShapePMIInfos> &oPMIInfos ,std::shared_ptr<PMI::InterOpPMIAnnotation> pmiInfo)
    {
		int nbLinks = iAnnotation.GetLinkedElementsCount();
	
		SPAIopEntityIter linksIter = iAnnotation.GetLinkedElementIterator( );
	#if 0
		const wchar_t *pIBufferArray = NULL;
		iBuffer.ToWChar(pIBufferArray);
		LOGGER_DEBUG("\n {} Linked Elements Count = {} \n", wstring_to_utf8(pIBufferArray), nbLinks);
	#endif
		int iLink = 0;
		while (linksIter.Next())
		{
			SPAIopEntity linkedEntity = linksIter.Current();
			// ProcessEntity(linkedEntity, iMappingData, iPSReferenceName, iBuffer);
			ENTITY* e = ProcessEntity(linkedEntity) ;
			std::string key = "-1" ;
			if (e){
				SPAIopAcisEntity acisIopEntity( e );
				SPAIopWString PIDW = acisIopEntity.GetPID();
				key = SPAIopWStringToString(PIDW);
			}
			LOGGER_DEBUG("pmi id: {}", key) ;
			if (oPMIInfos.find(key) != oPMIInfos.end()) {
				oPMIInfos[key].AddPMIInfo(pmiInfo) ;
			} else {
				PMI::InterOpShapePMIInfos info ;
				info.AddPMIInfo(pmiInfo) ;
				oPMIInfos.emplace(key, info) ;
				
			}
		}
    }

	// ENTITY*  ProcessEntity(SPAIopEntity& iEntity, SPAIopMappingData& iMappingData,const SPAIopWString& iPSReferenceName, SPAIopWString iBuffer)
	ENTITY*  ProcessEntity(SPAIopEntity& iEntity)
    {
		#if 0
		const wchar_t* pRefName = NULL;
		iPSReferenceName.ToWChar(pRefName);

		SPAIopWString compPathBuffer;
		SPAIopEntity partEntity;
		int compPathCounter = 0;
		SPAIopInputPSInstance partInst;
		ProcessLinkedEntity( iEntity, compPathBuffer, compPathCounter, partInst, partEntity);
		#endif
		SPAIopEntity partEntity;
		ProcessLinkedEntity( iEntity, partEntity);
		#if 0
		const wchar_t* pCompPathArray = NULL;
		compPathBuffer.ToWChar(pCompPathArray);
		wchar_t tmpCompPath[512];
		wcscpy( tmpCompPath, pRefName);
		SPAIopWString tabStr(L"\t\t\t");
		if( 0 < compPathCounter)
		{
			wcscat(tmpCompPath, L"!");
			wcscat(tmpCompPath, pCompPathArray);
			LOGGER_DEBUG("\t\t\t Comp_Entity Path={} \n", wstring_to_utf8(tmpCompPath));
			LOGGER_DEBUG("\t\t\t Part_Entity \n");
			tabStr = SPAIopWString( L"\t\t\t\t");

			SPAIopInputPSReference partRef = partInst.GetReference();
			unsigned int refId = partRef.GetUniqueID();
			// if( _inputPSRefMappingDataMap.find( refId) != _inputPSRefMappingDataMap.end()) 
			// 	iMappingData = *(_inputPSRefMappingDataMap[refId]);
		}
		const wchar_t *pTabStr = NULL;
		tabStr.ToWChar(pTabStr);
	
		const wchar_t *pBuffer = NULL;
		iBuffer.ToWChar( pBuffer );
		#endif
		SPAIopAcisEntity acisEntity =  (SPAIopAcisEntity&)partEntity;
		ENTITY* pAcisEntity = acisEntity.GetAcisEntity();
		#if 1
		if( NULL == pAcisEntity )
		{	
			LOGGER_DEBUG( "BRep_Entity not found. \n");
		}
		else
		{
			// SPAIopWString PIDW = acisEntity.GetPID();
			// const wchar_t* pPIDWC = NULL;
			// PIDW.ToWChar(pPIDWC);
			// tag_id_type pid  ;
			// api_get_entity_id(pAcisEntity,pid) ;
			// LOGGER_DEBUG( "BRep_Entity Persistent ID = {} \n", wstring_to_utf8(pPIDWC));
			// LOGGER_DEBUG( "BRep_Entity Persistent ID = {} \n",pid);
		}
		#endif
		// if( NULL!=SPAIopPMIUtils::ProcessPartEntityCBFct )
		// {
		// 	SPAIopPMIUtils::ProcessPartEntityCBFct( partEntity, tabStr);
		// }

		// ProcessOriginalEntityID(partEntity, iMappingData, pTabStr);
		return pAcisEntity ;
    }

	//========================================================================================================
	// void ProcessLinkedEntity(const SPAIopEntity& iEntity, SPAIopWString& ioCompPathBuffer, int& ioCompPathCounter,
	// 	SPAIopInputPSInstance& ioPartInstance, SPAIopEntity& ioPartEntity)
	void ProcessLinkedEntity( const SPAIopEntity& iEntity, SPAIopEntity& ioPartEntity)
	{
		bool isPartEntity = false;
		// LOG_DEBUG("ioCompPathBuffer: {} \n", SPAIopWStringToString(ioCompPathBuffer));

		SPAIopEntity partEntity;
		if( true == iEntity.GetPartEntity( partEntity))
		{
			ioPartEntity = partEntity;
		}
		else
		{
			SPAIopInstanceEntity instanceEntity;
			bool isInstEntity = false;
			isInstEntity = iEntity.GetInstanceEntity( instanceEntity);
			if( true == isInstEntity)
			{
			#if 0
				SPAIopInputPSInstance inputPSInst = instanceEntity.GetInstance();
				ioPartInstance = inputPSInst;
				SPAIopWString instName = inputPSInst.GetInstanceName();
				const wchar_t* pInstName = NULL;
				instName.ToWChar(pInstName);

				SPAIopWString tempBuffer = ioCompPathBuffer;

				const wchar_t* pcompPathBuffer = NULL;
				tempBuffer.ToWChar(pcompPathBuffer);
				wchar_t tmpBuffer[512];
				wcscpy( tmpBuffer, pcompPathBuffer);
				if( 0 < ioCompPathCounter)
					wcscat( tmpBuffer, L"!");
				wcscat( tmpBuffer, pInstName);

				ioCompPathBuffer = SPAIopWString( tmpBuffer);
			#endif

				SPAIopEntity pChildEntity = instanceEntity.GetEntity();
				ProcessLinkedEntity( pChildEntity, ioPartEntity);
			}
			else
			{
				LOG_DEBUG("WARNING: Unhandled Entity type detected \n");
			}
		}
	}

    void ToString( SPAIopPMIRoughnessObtentionType iObtentionType, SPAIopWString& oObtentionType)
	{
		switch( iObtentionType)
		{
			case SPAIopPMI_RO_UnSupported:
				oObtentionType = SPAIopWString( L"SPAIopPMI_RO_UnSupported");
				break;
			case SPAIopPMI_RO_NotDefined:
				oObtentionType = SPAIopWString( L"SPAIopPMI_RO_NotDefined");
				break;
			case SPAIopPMI_RO_MachiningMandatory:
				oObtentionType = SPAIopWString( L"SPAIopPMI_RO_MachiningMandatory");
				break;
			case SPAIopPMI_RO_MachiningForbidden:
				oObtentionType = SPAIopWString( L"SPAIopPMI_RO_MachiningForbidden");
				break;
			default:
				oObtentionType = SPAIopWString( L"SPAIopPMI_UNKNOWN");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIRoughnessApplicabilityType iApplicabilityType, SPAIopWString& oApplicabilityType)
	{
		switch( iApplicabilityType)
		{
			case SPAIopPMI_RA_UnSupported:
				oApplicabilityType = SPAIopWString( L"SPAIopPMI_RA_UnSupported");
				break;
			case SPAIopPMI_RA_SpecifiedSurfaceOnly:
				oApplicabilityType = SPAIopWString( L"SPAIopPMI_RA_SpecifiedSurfaceOnly");
				break;
			case SPAIopPMI_RA_AllPartSurfaces:
				oApplicabilityType = SPAIopWString( L"SPAIopPMI_RA_AllPartSurfaces");
				break;
			case SPAIopPMI_RA_BasicSurface:
				oApplicabilityType = SPAIopWString( L"SPAIopPMI_RA_BasicSurface");
				break;
			default:
				oApplicabilityType = SPAIopWString( L"SPAIopPMI_UNKNOWN");
		}
	}

	//========================================================================================================
	
	void ToString( SPAIopPMIToleranceType iToleranceType, SPAIopWString& oTolType)
	{
		switch( iToleranceType)
		{
			case SPAIopPMI_Form_Straightness:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_Straightness");
				break;
			case SPAIopPMI_Form_Flatness:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_Flatness");
				break;
			case SPAIopPMI_Form_Circularity:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_Circularity");
				break;
			case SPAIopPMI_Form_Cylindricity:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_Cylindricity");
				break;
			case SPAIopPMI_Form_ProfileAnyLine:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_ProfileAnyLine");
				break;
			case SPAIopPMI_Form_ProfileAnySurface:
				oTolType = SPAIopWString( L"SPAIopPMI_Form_ProfileAnySurface");
				break;
			case SPAIopPMI_Orientation_Parallelism:
				oTolType = SPAIopWString( L"SPAIopPMI_Orientation_Parallelism");
				break;
			case SPAIopPMI_Orientation_Perpendicularity:
				oTolType = SPAIopWString( L"SPAIopPMI_Orientation_Perpendicularity");
				break;
			case SPAIopPMI_Orientation_Angularity:
				oTolType = SPAIopWString( L"SPAIopPMI_Orientation_Angularity");
				break;
			case SPAIopPMI_Location_TruePosition:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_TruePosition");
				break;
			case SPAIopPMI_Location_Concentricity:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_Concentricity");
				break;
			case SPAIopPMI_Location_Coaxiality:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_Coaxiality");
				break;
			case SPAIopPMI_Location_Symmetry:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_Symmetry");
				break;
			case SPAIopPMI_Location_PositionOfAnyLine:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_PositionOfAnyLine");
				break;
			case SPAIopPMI_Location_PositionOfASurface:
				oTolType = SPAIopWString( L"SPAIopPMI_Location_PositionOfASurface");
				break;
			case SPAIopPMI_RunOut_Circular:
				oTolType = SPAIopWString( L"SPAIopPMI_RunOut_Circular");
				break;
			case SPAIopPMI_RunOut_Total:
				oTolType = SPAIopWString( L"SPAIopPMI_RunOut_Total");
				break;
			default:
				oTolType = SPAIopWString( L"SPAIopPMI_TOLTYPE_UNKNOWN");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIToleranceValueType iToleranceValueType, SPAIopWString& oTolValType)
	{
		switch( iToleranceValueType)
		{
			case SPAIopPMI_ValueType_None:
				oTolValType = SPAIopWString( L"SPAIopPMI_ValueType_None");
				break;
			case SPAIopPMI_ValueType_Diameter:
				oTolValType = SPAIopWString( L"SPAIopPMI_ValueType_Diameter");
				break;
			case SPAIopPMI_ValueType_Radius:
				oTolValType = SPAIopWString( L"SPAIopPMI_ValueType_Radius");
				break;
			case SPAIopPMI_ValueType_Spherical:
				oTolValType = SPAIopWString( L"SPAIopPMI_ValueType_Spherical");
				break;
			case SPAIopPMI_ValueType_Square:
				oTolValType = SPAIopWString( L"SPAIopPMI_ValueType_Square");
				break;
			default:
				oTolValType = SPAIopWString( L"SPAIopPMI_TOLVALTYPE_UNKNOWN");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIToleranceModifier iZoneModifier, SPAIopWString& oZoneModifier)
	{
		switch( iZoneModifier)
		{
			case SPAIopPMI_MaterialCondition_Unsupported:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_MaterialCondition_Unsupported");
				break;
			case SPAIopPMI_MaterialCondition_NoModifier:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_MaterialCondition_NoModifier");
				break;
			case SPAIopPMI_MaterialCondition_Maximum:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_MaterialCondition_Maximum");
				break;
			case SPAIopPMI_MaterialCondition_Least:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_MaterialCondition_Least");
				break;
			case SPAIopPMI_MaterialCondition_RegardlessOfFeatureSize:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_MaterialCondition_RegardlessOfFeatureSize");
				break;
			case SPAIopPMI_TangentPlane_Unsupported:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_TangentPlane_Unsupported");
				break;
			case SPAIopPMI_TangentPlane_NotTangent:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_TangentPlane_NotTangent");
				break;
			case SPAIopPMI_TangentPlane_Tangent:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_TangentPlane_Tangent");
				break;
			case SPAIopPMI_FreeState_Unsupported:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_FreeState_Unsupported");
				break;
			case SPAIopPMI_FreeState_Free:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_FreeState_Free");
				break;
			case SPAIopPMI_FreeState_NotFree:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_FreeState_NotFree");
				break;
			case SPAIopPMI_Statistical_Symbol:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_Statistical_Symbol");
				break;
			case SPAIopPMI_CommonZone:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_CommonZone");
				break;
			case SPAIopPMI_UnequallyDisposedZone:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_UnequallyDisposedZone");
				break;
			case SPAIopPMI_ProjectedState_Projected:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_ProjectedState_Projected");
				break;
			case SPAIopPMI_ProjectedState_NotProjected:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_ProjectedState_NotProjected");
				break;
			case SPAIopPMI_CircleU:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_CircleU");
				break;
			case SPAIopPMI_Maximum:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_Maximum");
				break;
			case SPAIopPMI_MinimaxFeature:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimaxFeature");
				break;
			case SPAIopPMI_DerivedFeature:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_DerivedFeature");
				break;
			case SPAIopPMI_DynamicProfile:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_DynamicProfile");
				break;
			case SPAIopPMI_LeastSquareFeature:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_LeastSquareFeature");
				break;
			case SPAIopPMI_MaximumInscribedFeature:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MaximumInscribedFeature");
				break;
			case SPAIopPMI_MinimumCircumscribedFeature:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimumCircumscribedFeature");
				break;
			case SPAIopPMI_SeparateZone:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_SeparateZone");
				break;
			case SPAIopPMI_OffsetZone:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_OffsetZone");
				break;
			case SPAIopPMI_VariableAngle:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_VariableAngle");
				break;
			case SPAIopPMI_OrientationConstraint:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_OrientationConstraint");
				break;
			case SPAIopPMI_MinimaxAssociation:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimaxAssociation");
				break;
			case SPAIopPMI_MinimaxAssociationWithExternalConstraint:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimaxAssociationWithExternalConstraint");
				break;
			case SPAIopPMI_MinimaxAssociationWithInternalConstraint:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimaxAssociationWithInternalConstraint");
				break;
			case SPAIopPMI_LeastSquareAssociation:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_LeastSquareAssociation");
				break;
			case SPAIopPMI_LeastSquareAssociationWithExternalConstraint:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_LeastSquareAssociationWithExternalConstraint");
				break;
			case SPAIopPMI_LeastSquareAssociationWithInternalConstraint:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_LeastSquareAssociationWithInternalConstraint");
				break;
			case SPAIopPMI_MinimumCircumscribedAssociation:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MinimumCircumscribedAssociation");
				break;
			case SPAIopPMI_MaximumInscribedAssociation:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_MaximumInscribedAssociation");
				break;
			case SPAIopPMI_TotalRangeOfDeviations:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_TotalRangeOfDeviations");
				break;
			case SPAIopPMI_PeakHeight:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_PeakHeight");
				break;
			case SPAIopPMI_ValleyDepth:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_ValleyDepth");
				break;
			case SPAIopPMI_StandardDeviation:
				oZoneModifier = SPAIopWString(L"SPAIopPMI_StandardDeviation");
				break;
			default:
				oZoneModifier = SPAIopWString( L"SPAIopPMI_NoModifier");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIDimensionMainType iDimMainType, SPAIopWString& oDimMainType)
	{
		switch( iDimMainType)
		{
			case SPAIopPMI_DMT_Basic:
				oDimMainType = SPAIopWString( L"SPAIopPMI_DMT_Basic");
				break;
			case SPAIopPMI_DMT_Reference:
				oDimMainType = SPAIopWString( L"SPAIopPMI_DMT_Reference");
				break;
			case SPAIopPMI_DMT_Tolerance:
				oDimMainType = SPAIopWString( L"SPAIopPMI_DMT_Tolerance");
				break;
			case SPAIopPMI_DMT_CoordDim:
				oDimMainType = SPAIopWString( L"SPAIopPMI_DMT_CoordDim");
				break;
			case SPAIopPMI_DMT_HoleCallout:
				oDimMainType = SPAIopWString(L"SPAIopPMI_DMT_HoleCallout");
				break;
			default:
				oDimMainType = SPAIopWString( L"SPAIopPMI_DMT_Unknown");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIDimensionSubType iDimSubType, SPAIopWString& oDimSubType)
	{
		switch( iDimSubType)
		{
			case SPAIopPMI_Distance:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Distance");
				break;
			case SPAIopPMI_DistanceOffset:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DistanceOffset");
				break;
			case SPAIopPMI_Length:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Length");
				break;
			case SPAIopPMI_Length_OR_Distance:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Length_OR_Distance");
				break;
			case SPAIopPMI_LengthCurvilinear:
				oDimSubType = SPAIopWString( L"SPAIopPMI_LengthCurvilinear");
				break;
			case SPAIopPMI_Angle:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Angle");
				break;
			case SPAIopPMI_Radius:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Radius");
				break;
			case SPAIopPMI_RadiusTangent:
				oDimSubType = SPAIopWString( L"SPAIopPMI_RadiusTangent");
				break;
			case SPAIopPMI_RadiusCylinder:
				oDimSubType = SPAIopWString( L"SPAIopPMI_RadiusCylinder");
				break;
			case SPAIopPMI_RadiusEdge:
				oDimSubType = SPAIopWString( L"SPAIopPMI_RadiusEdge");
				break;
			case SPAIopPMI_Diameter:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Diameter");
				break;
			case SPAIopPMI_DiameterTangent:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DiameterTangent");
				break;
			case SPAIopPMI_DiameterCylinder:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DiameterCylinder");
				break;
			case SPAIopPMI_DiameterEdge:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DiameterEdge");
				break;
			case SPAIopPMI_DiameterCone:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DiameterCone");
				break;
			case SPAIopPMI_Chamfer:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Chamfer");
				break;
			case SPAIopPMI_Slope:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Slope");
				break;
			case SPAIopPMI_DimGDT:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DimGDT");
				break;
			case SPAIopPMI_DimDatumFeature:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DimDatumFeature");
				break;
			case SPAIopPMI_DimDatumTarget:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DimDatumTarget");
				break;
			case SPAIopPMI_DimBalloon:
				oDimSubType = SPAIopWString( L"SPAIopPMI_DimBalloon");
				break;
			case SPAIopPMI_No_Dim:
				oDimSubType = SPAIopWString( L"SPAIopPMI_No_Dim");
				break;
			case SPAIopPMI_AngleArc:
				oDimSubType = SPAIopWString( L"SPAIopPMI_AngleArc");
				break;
			case SPAIopPMI_LengthCircular:
				oDimSubType = SPAIopWString( L"SPAIopPMI_LengthCircular");
				break;
			case SPAIopPMI_Fillet:
				oDimSubType = SPAIopWString( L"SPAIopPMI_Fillet");
				break;
			case SPAIopPMI_CoordDimension_2D:
				oDimSubType = SPAIopWString( L"SPAIopPMI_CoordDimension_2D");
				break;
			case SPAIopPMI_CoordDimension_3D:
				oDimSubType = SPAIopWString( L"SPAIopPMI_CoordDimension_3D");
				break;
			default:
				oDimSubType = SPAIopWString( L"SPAIopPMI_UNKNOWN");
		}
	}

	//========================================================================================================
	
	void ToString(SPAIopPMICalloutFeatureAnnotationType iCalloutFeatureAnnotType, SPAIopWString& oCalloutFeatureAnnotType)
	{
		switch (iCalloutFeatureAnnotType)
		{
		case SPAIopPMI_FEATURETYPE_UNKNOWN:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_UNKNOWN");
			break;
		case SPAIopPMI_FEATURETYPE_HOLE_UNKNOWN:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLE_UNKNOWN");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTFIT:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTFIT");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTDEPTH:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTDEPTH");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTDIAMETER:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTDIAMETER");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTSCREWSIZE:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTSCREWSIZE");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERBOREDEPTH:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERBOREDEPTH");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERBOREDIAMETER:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERBOREDIAMETER");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTPATTERNCOUNT:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTPATTERNCOUNT");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTPITCH:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTPITCH");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTANGLE:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTANGLE");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTPATTAPERANGLE:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTPATTAPERANGLE");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERSINKDIAMETER:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTCOUNTERSINKDIAMETER");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTPATCOUNTERSINKANGLE:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTPATCOUNTERSINKANGLE");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADDEPTH:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADDEPTH");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADSIZE:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADSIZE");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADMINORDIA:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADMINORDIA");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADMAJORDIA:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTTHREADMAJORDIA");
			break;
		case SPAIopPMI_FEATURETYPE_HOLECALLOUTTAPDRILLDIA:
			oCalloutFeatureAnnotType = SPAIopWString(L"SPAIopPMI_FEATURETYPE_HOLECALLOUTTAPDRILLDIA");
			break;
		default:
			break;
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIUnit iUnit, SPAIopWString& oUnit)
	{
		switch( iUnit)
		{
			case SPAIopPMI_DimUnitMM:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitMM");
				break;
			case SPAIopPMI_DimUnitINCH:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitINCH");
				break;
			case SPAIopPMI_DimUnitMETER:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitMETER");
				break;
			case SPAIopPMI_DimUnitCM:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitCM");
				break;
			case SPAIopPMI_DimUnitKM:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitKM");
				break;
			case SPAIopPMI_DimUnitFOOT:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitFOOT");
				break;
			case SPAIopPMI_DimUnitF_I_F64:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitF_I_F64");
				break;
			case SPAIopPMI_DimUnitF_I_F16:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitF_I_F16");
				break;
			case SPAIopPMI_DimUnitF_I_DEC:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitF_I_DEC");
				break;
			case SPAIopPMI_DimUnitDEGREE:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitDEGREE");
				break;
			case SPAIopPMI_DimUnitMINUTE:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitMINUTE");
				break;
			case SPAIopPMI_DimUnitSECOND:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitSECOND");
				break;
			case SPAIopPMI_DimUnitRADIAN:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitRADIAN");
				break;
			case SPAIopPMI_DimUnitGRADE:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitGRADE");
				break;
			default:
				oUnit = SPAIopWString( L"SPAIopPMI_DimUnitNone");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIArrowSymbol iArrowSymbol, SPAIopWString& oArrowSymbol)
	{
		switch( iArrowSymbol)
		{
			case SPAIopPMI_CROSS:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_CROSS");
				break;
			case SPAIopPMI_PLUS:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_PLUS");
				break;
			case SPAIopPMI_CONCENTRIC:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_CONCENTRIC");
				break;
			case SPAIopPMI_COINCIDENT:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_COINCIDENT");
				break;
			case SPAIopPMI_FULLCIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FULLCIRCLE");
				break;
			case SPAIopPMI_FULLSQUARE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FULLSQUARE");
				break;
			case SPAIopPMI_STAR:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_STAR");
				break;
			case SPAIopPMI_DOT:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_DOT");
				break;
			case SPAIopPMI_SMALLDOT:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_SMALLDOT");
				break;
			case SPAIopPMI_MISC1:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MISC1");
				break;
			case SPAIopPMI_MISC2:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MISC2");
				break;
			case SPAIopPMI_FULLCIRCLE2:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FULLCIRCLE2");
				break;
			case SPAIopPMI_FULLSQUARE2:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FULLSQUARE2");
				break;
			case SPAIopPMI_OPEN_ARROW:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_OPEN_ARROW");
				break;
			case SPAIopPMI_UNFILLED_ARROW:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_UNFILLED_ARROW");
				break;
			case SPAIopPMI_BLANKED_ARROW:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_BLANKED_ARROW");
				break;
			case SPAIopPMI_FILLED_ARROW:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FILLED_ARROW");
				break;
			case SPAIopPMI_UNFILLED_CIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_UNFILLED_CIRCLE");
				break;
			case SPAIopPMI_BLANKED_CIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_BLANKED_CIRCLE");
				break;
			case SPAIopPMI_FILLED_CIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FILLED_CIRCLE");
				break;
			case SPAIopPMI_CROSSED_CIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_CROSSED_CIRCLE");
				break;
			case SPAIopPMI_BLANKED_SQUARE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_BLANKED_SQUARE");
				break;
			case SPAIopPMI_FILLED_SQUARE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FILLED_SQUARE");
				break;
			case SPAIopPMI_BLANKED_TRIANGLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_BLANKED_TRIANGLE");
				break;
			case SPAIopPMI_FILLED_TRIANGLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_FILLED_TRIANGLE");
				break;
			case SPAIopPMI_MANIPULATOR_SQUARE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MANIPULATOR_SQUARE");
				break;
			case SPAIopPMI_MANIPULATOR_DIAMOND:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MANIPULATOR_DIAMOND");
				break;
			case SPAIopPMI_MANIPULATOR_CIRCLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MANIPULATOR_CIRCLE");
				break;
			case SPAIopPMI_MANIPULATOR_TRIANGLE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_MANIPULATOR_TRIANGLE");
				break;
			case SPAIopPMI_DOUBLE_OPEN_ARROW:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_DOUBLE_OPEN_ARROW");
				break;
			case SPAIopPMI_WAVE:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_WAVE");
				break;
			default:
				oArrowSymbol = SPAIopWString( L"SPAIopPMI_NOTUSED");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMICameraType iCameraType, SPAIopWString& oCameraType)
	{
		switch( iCameraType)
		{
			case SPAIopPMI_Camera_Perspective:
				oCameraType = SPAIopWString( L"SPAIopPMI_Camera_Perspective");
				break;
			case SPAIopPMI_Camera_Orthographic:
				oCameraType = SPAIopWString( L"SPAIopPMI_Camera_Orthographic");
				break;
			default:
				oCameraType = SPAIopWString( L"SPAIopPMI_Camera_Unknown");
		}
	}

	//========================================================================================================

	void ToString( SPAIopPMIAnnotationType iAnnotType, SPAIopWString& oAnnotType)
	{
		switch( iAnnotType)
		{
			case SPAIopPMI_Datum:
				oAnnotType = SPAIopWString( L"SPAIopPMI_Datum");
				break;
			case SPAIopPMI_DatumTarget:
				oAnnotType = SPAIopWString( L"SPAIopPMI_DatumTarget");
				break;
			case SPAIopPMI_Note:
				oAnnotType = SPAIopWString( L"SPAIopPMI_Note");
				break;
			case SPAIopPMI_FlagNote:
				oAnnotType = SPAIopWString( L"SPAIopPMI_FlagNote");
				break;
			case SPAIopPMI_NOA:
				oAnnotType = SPAIopWString( L"SPAIopPMI_NOA");
				break;
			case SPAIopPMI_Roughness:
				oAnnotType = SPAIopWString( L"SPAIopPMI_Roughness");
				break;
			case SPAIopPMI_GDT:
				oAnnotType = SPAIopWString( L"SPAIopPMI_GDT");
				break;
			case SPAIopPMI_Dimension:
				oAnnotType = SPAIopWString( L"SPAIopPMI_Dimension");
				break;
			default:
				oAnnotType = SPAIopWString( L"SPAIopPMI_UnknownType");
		}
	}
	
	//========================================================================================================

	void ToString( SPAIopPMIOrientation iOrientation, SPAIopWString& oOrientation)
	{
		switch( iOrientation)
		{
			case SPAIopPMI_Horizontal:
				oOrientation = SPAIopWString( L"SPAIopPMI_Horizontal");
				break;
			case SPAIopPMI_Vertical:
				oOrientation = SPAIopWString( L"SPAIopPMI_Vertical");
				break;
			case SPAIopPMI_Parallel:
				oOrientation = SPAIopWString( L"SPAIopPMI_Parallel");
				break;
			case SPAIopPMI_Perpendicular:
				oOrientation = SPAIopWString( L"SPAIopPMI_Perpendicular");
				break;
			case SPAIopPMI_DimAngle:
				oOrientation = SPAIopWString( L"SPAIopPMI_DimAngle");
				break;
			default:
				oOrientation = SPAIopWString( L"SPAIopPMI_UNKNOWN");
		}
	}

}

AMCAX_EXCHANGE_NAMESPACE_END